Обнаружил утечки памяти при тестировании на исторических данных, при многократном повторении. Сначал грешил на свою стратегию, потом попробовал запускать пример SampleHistoryTesting многократно, При достижении 30-40 повторений программа подвисала, не выдавая никаких сообщений.
Далее, для чистоты эксперимента подправил код SampleHistoryTesting:
private void StartBtn_Click( object sender, RoutedEventArgs e ) {
for( int i = 1; i < 1000; i++ ) {
Run();
if( _trader.State != EmulationStates.Started ) { Thread.Sleep( 10 ); }
if( _trader.State != EmulationStates.Stopped ) { Thread.Sleep( 10 ); }
}
MessageBox.Show( "Закончено" );
}
private void Run()
{
// Ну а тут сам код стратегии, что был раньше в StartBtn_Click
...
// изменил только период, для более быстрого тестирования
var startTime = new DateTime(2009, 6, 1);
var stopTime = new DateTime(2009, 6, 3);
....
}
После запуска данный код через некоторое время выдает Out of memory эксепшн. (Пробовал, как с включенным выводом инфы в форму, так и выключеным)
на 100 итерациях уже все нормально проходит.
Памяти достаточно - 4 гб озу
Текст исключения:
System.OutOfMemoryException: Выдано исключение типа "System.OutOfMemoryException".
в System.Linq.Buffer1.ToArray() в System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source)
в Ecng.Common.RandomArray1..ctor(T min, T max, Int32 count) в StockSharp.Algo.Testing.MarketDataGenerator1.Init()
в StockSharp.Algo.Testing.TrendMarketDepthGenerator.Init()
в StockSharp.Algo.Testing.EmulationTrader.Start(DateTime startDate, DateTime stopDate)
в SampleHistoryTesting.MainWindow.Run() в C:\Projects\VS\OrigSampleHistoryTesting\MainWindow.xaml.cs:строка 219
в SampleHistoryTesting.MainWindow.StartBtn_Click(Object sender, RoutedEventArgs e) в C:\Projects\VS\OrigSampleHistoryTesting\MainWindow.xaml.cs:строка 63
в System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
в System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
в System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
в System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
в System.Windows.Controls.Primitives.ButtonBase.OnClick()
в System.Windows.Controls.Button.OnClick()
в System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
в System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
в System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
в System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
в System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
в System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
в System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
в System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
в System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
в System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
в System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
в System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
в System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
в System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
в System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
в System.Windows.Input.InputManager.ProcessStagingArea()
в System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
в System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
в System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
в System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
в System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
в MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
в MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
в System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
в MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
コメント (25)
ログイン または アカウントを作成, コメントを残すにはログインまたは新規登録してください
Спасибо посмотрим. Это какая версия S#? В 4.1 у нас новый тестер. Лучше его использовать. Называется LowMemEmulationTrader
Уже переименован в EmulationTrader
Проверял на 4.0.19 и 4.0.23
А где взять версию 4.1 ? в box.com пока вижу последнюю версию 4.0.23
Codeplex, папка dev
Скачал новую версию, и запустил в ней SampleHistoryTesting. В ответ тишина, т.е. кривая эквилити не обновляется. Сообщение о том, что расчет закончен не отображается. На предыдущих версиях данный пример работал
4.1? Архив с данными тоже был скачал новый?
архив данных от 4.0 при попытке запустить гидру, получаю ошибку, о которой отписался в соответствующем разделе
данные менялись, используйте новые
У меня на 4.1 в примере SampleHistoryTesting утечка памяти тоже возникает. Может нужно какие-нть данные представить по использованию памяти?
Конечно нужно. Какой интервал тестирования, сколько памяти потребляло в 4.0, сколько потребляет в 4.1. Какая конкретно версия с codeplex.
Интервал тестирования не менял (стоит с 01.06.2009 по 01.09.2009) На 4.0.0.23 в пике 2174012 Кб На 4.1 (с codeplex stocksharp-17261.zip) в пике 2117100 Кб
Аналогичная ситуация. Если запускать трейдер много раз, возникало исключение OutOfMemory. С каждой новой итерацией оказывалось съеденным все больше памяти.
После танцев с бубном удалось выяснить, что проблема в буфере экземпляра EmulationTrader - приватное поле типа Ecng.Collections.BlockingQueue<>. Стало ясно, что объекты данной коллекции остаются в памяти, сборщик мусора почему-то их не трогает. При запуске каждого нового экземпляра EmulationTrader объем занимаемой памяти растет. Уменьшение свойства BufferSize приводит к уменьшению размера прироста памяти, но проблема остается. Решил проблему очисткой буфера в методе Dispose() MyClass (прирост занятой памяти или вообще прекратился или сильно замедлился):
var value= _trader.GetType().GetField("#=qtcoS5HXJh4KLzrXhXg6zgg==", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(_trader); value.GetType().GetMethod("Clear").Invoke(value, null); _trader.Dispose();
Думаю, если очищать буфер в методе Dispose класса EmulationTrader, хуже не станет.
alexeev.evg,
из вашего кода несовсем ясно, сколько экземпляров EmulationTrader используется?
конструкция <code> using (var temp = new MyClass()) { temp.StartTest(date1, date2); } </code>
как мне кажется стартует EmulationTrader и сразу его останавливает в Dispose не дожидаясь пока он дотестирует.
Вы можете привести полный код примера чтобы я мог воспроизвести утечку?
А между тем, проблема с EmulationTrader осталась и в последней версии S# (4.1.7.0). Если запускать тестирование с включенной генерацией стакана - обычно ±150 созданных и затем даже принудительно удаленных EmulationTrader'ов хватает чтобы заполнить ±1200 MB оперативы (после очень скоро следует OutOfMemoryEx).
Виновником, как я думаю, является TrendMarketDepthGenerator, содержащий объект(ы) типа Ecng.Common.RandomArray, которые по какой-то причине не очищаются GC, но при этом содержат и накапливают огромное количество [int]. На картинке - состояние приложения после прогона на 48 EmulationTrader'ах и удалении каждого. 89% занимают неудаленные массивы:
Если сделать нечто, предложенное alexeev.evg выше, при удалении EmulationTrader'а (взял первый попавшийся объект содержащий Ecng.Common.RandomArray), для последней версии S# это:
То занимая память приложения уменьшится примерно вдвое.
Коллеги, можете посмотреть, что с этим можно сделать?
Та же фигня. Пол дня искал в своем коде утечки, пока на форум не зашел=/
На последней версии воспроизводиться?
ak выше писал "А между тем, проблема с EmulationTrader осталась и в последней версии S# (4.1.7.0). "
Я про кодеплекс.
Хорошая статейка http://msdn.microsoft.com/en-us/magazine/jj863136.aspx В самом низу есть список новых потоконезависимых коллекций .net 4.0 Как вариант замены деревянных велосипедов.
А кто-нить в S# тестил разницу между SynchronizedDictionary и ConcurrentDictionary?
Потестил на последней сборке #22766 - но моих тестах ситуация изменилась кардинально.
Тестировал на 48 EmulationTrader'ах и 3 торговых днях.
Предыдущая версия (не уверен, что 4.1.7.0, возможно я обновлялся из trunk'а): Пиковое потребление: 1200+ МБ Потребление после завершения теста и удаления EmulationTrader'ов: ~600 МБ
Новая версия: #22766 Пиковое потребление: ~500 МБ Потребление после завершения теста и удаления EmulationTrader'ов: ~140 МБ
Спасибо. Позже я еще внимательно посмотрю на CandleManagerContainer, может и он подтекает )
Мне не помогло. Взял с кодеплекса последний changeset 22848, референсы с транка, версия 4.1.8. Один прогон теста на данных ордерлога за месяц занимают 2Гб, затем делаю Dispose всему чему могу, экземпляру трейдера в том числе, делаю GC.Collect() на всякий случай, память занимаемая приложением не уменьшается. Затем запускается новый прогон теста на том же месяце, память уходит за 7Гб, комп помирает
Нужно убедиться, что все объекты входящие в конструирование трейдера нигде не остаются висеть, внимательно просмотрите у себя:
Особенно обратите внимание на marketDepthGenerator = null; - из объекта трейдера его не достать никак, поэтому я прицепил этот обработчик в scope'е где у меня есть доступ к только что созданному локальному объекту marketDepthGenerator.
Воспользуйтесь CLR Profiler (http://www.microsoft.com/en-us/download/details.aspx?id=16273), он позволяет очень наглядно посмотреть Managed Heap для запущенного приложения - сразу станет понятно, где течет.