Утечки памяти при тестировании на исторических данных

Утечки памяти при тестировании на исторических данных
Atom
4/2/2012


Обнаружил утечки памяти при тестировании на исторических данных, при многократном повторении.
Сначал грешил на свою стратегию, потом попробовал запускать пример SampleHistoryTesting многократно,
При достижении 30-40 повторений программа подвисала, не выдавая никаких сообщений.

Далее, для чистоты эксперимента подправил код SampleHistoryTesting:

Code
		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.Buffer`1.ToArray()
в System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
в Ecng.Common.RandomArray`1..ctor(T min, T max, Int32 count)
в StockSharp.Algo.Testing.MarketDataGenerator`1.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)




Thanks:


< 1 2 3  >
paveld

Avatar
Date: 5/25/2012
Reply


У меня на 4.1 в примере SampleHistoryTesting утечка памяти тоже возникает. Может нужно какие-нть данные представить по использованию памяти?
Thanks:

Alexander

Avatar
Date: 5/25/2012
Reply


paveld Go to
У меня на 4.1 в примере SampleHistoryTesting утечка памяти тоже возникает. Может нужно какие-нть данные представить по использованию памяти?


Конечно нужно. Какой интервал тестирования, сколько памяти потребляло в 4.0, сколько потребляет в 4.1.
Какая конкретно версия с codeplex.
Thanks:

paveld

Avatar
Date: 5/25/2012
Reply


Alexander Mukhanchikov Go to
paveld Go to
У меня на 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 Кб

Thanks:

alexeev.evg

Avatar
Date: 6/30/2012
Reply


Аналогичная ситуация. Если запускать трейдер много раз, возникало исключение OutOfMemory. С каждой новой итерацией оказывалось съеденным все больше памяти.
Code

static void Main(string[] args)
{
	for (int i = 1; i <= 100; i ++)
	{
		using (var temp = new MyClass())
		{
			temp.StartTest(date1, date2);
		}
		GC.Collect();
		GC.WaitForFullGCComplete();
		//с каждой новой итерацией занятая память в этой точке растет
	}
	Console.ReadLine();
}

public class MyClass : IDisposable
{
	private Security _security1;
	private Security _security2;
	private Portfolio _portfolio;
	private MarketDepth _depth1;
	private MarketDepth _depth2;
	private BaseTrader _trader;

	public MyClass()
	{
	}

	public void StartTest(DateTime date1, DateTime date2)
	{
		//запуск трейдера
	}

	public void Dispose()
	{
		if (_trader != null)
		_	trader.Dispose();
		_security1 = null;
		_security2 = null;
		_portfolio = null;
		_depth1 = null;
		_depth2 = null;
		_trader = null;
	}
}


После танцев с бубном удалось выяснить, что проблема в буфере экземпляра 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, хуже не станет.
Thanks:

pyhta4og

Avatar
Date: 7/2/2012
Reply


alexeev.evg,

из вашего кода несовсем ясно, сколько экземпляров EmulationTrader используется?

конструкция
<code>
using (var temp = new MyClass())
{
temp.StartTest(date1, date2);
}
</code>

как мне кажется стартует EmulationTrader и сразу его останавливает в Dispose не дожидаясь пока он дотестирует.

Вы можете привести полный код примера чтобы я мог воспроизвести утечку?
Thanks:

ak

Avatar
Date: 1/28/2013
Reply


А между тем, проблема с EmulationTrader осталась и в последней версии S# (4.1.7.0). Если запускать тестирование с включенной генерацией стакана - обычно ±150 созданных и затем даже принудительно удаленных EmulationTrader'ов хватает чтобы заполнить ±1200 MB оперативы (после очень скоро следует OutOfMemoryEx).

Виновником, как я думаю, является TrendMarketDepthGenerator, содержащий объект(ы) типа Ecng.Common.RandomArray, которые по какой-то причине не очищаются GC, но при этом содержат и накапливают огромное количество [int]. На картинке - состояние приложения после прогона на 48 EmulationTrader'ах и удалении каждого. 89% занимают неудаленные массивы:

Click for large view - Uploaded with Skitch

Если сделать нечто, предложенное alexeev.evg выше, при удалении EmulationTrader'а (взял первый попавшийся объект содержащий Ecng.Common.RandomArray), для последней версии S# это:

Code

// try to cleanup memory, private field in EmulationTrader
//{Ecng.Collections.CachedSynchronizedDictionary<StockSharp.BusinessEntities.Security,StockSharp.Algo.Testing.MarketDepthGenerator>} 
var value = context.Value.Trader.GetType().GetField("#=qHvivsYU2tNspR3_h$VF0nqA$yDC50HFX_RHAxeUi6UE=", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(context.Value.Trader);
value.GetType().GetMethod("Clear").Invoke(value, null);

context.Value.Trader.Dispose();
context.Value.Trader = null;


То занимая память приложения уменьшится примерно вдвое.

Коллеги, можете посмотреть, что с этим можно сделать?
Thanks: Геннадий Ванин (Gennady Vanin)

FiNick

Avatar
Date: 2/1/2013
Reply


Та же фигня. Пол дня искал в своем коде утечки, пока на форум не зашел=/
Thanks: Геннадий Ванин (Gennady Vanin)

VassilSanych

Avatar
Date: 2/1/2013
Reply


Хорошая статейка
http://msdn.microsoft.co.../magazine/jj863136.aspx
В самом низу есть список новых потоконезависимых коллекций .net 4.0
Как вариант замены деревянных велосипедов.
Thanks: Den Геннадий Ванин (Gennady Vanin)

Den

Avatar
Date: 2/1/2013
Reply


VassilSanych Go to
Хорошая статейка
http://msdn.microsoft.co.../magazine/jj863136.aspx
В самом низу есть список новых потоконезависимых коллекций .net 4.0
Как вариант замены деревянных велосипедов.


А кто-нить в S# тестил разницу между SynchronizedDictionary и ConcurrentDictionary?
Thanks:

Mikhail Sukhov

Avatar
Date: 2/1/2013
Reply


FiNick Go to
Та же фигня. Пол дня искал в своем коде утечки, пока на форум не зашел=/


На последней версии воспроизводиться?
Thanks:
< 1 2 3  >

Attach files by dragging & dropping, , or pasting from the clipboard.

loading
clippy