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


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


Обнаружил утечки памяти при тестировании на исторических данных, при многократном повторении.
Сначал грешил на свою стратегию, потом попробовал запускать пример 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.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)




Спасибо:


< 1 2 3  >
paveld

Фотография
Дата: 25.05.2012
Ответить


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

Alexander

Фотография
Дата: 25.05.2012
Ответить


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


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

paveld

Фотография
Дата: 25.05.2012
Ответить


Alexander Mukhanchikov Перейти
paveld Перейти
У меня на 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 Кб

Спасибо:

alexeev.evg

Фотография
Дата: 30.06.2012
Ответить


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

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, хуже не станет.
Спасибо:

pyhta4og

Фотография
Дата: 02.07.2012
Ответить


alexeev.evg,

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

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

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

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

ak

Фотография
Дата: 28.01.2013
Ответить


А между тем, проблема с 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# это:

Код

// 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;


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

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

FiNick

Фотография
Дата: 01.02.2013
Ответить


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

VassilSanych

Фотография
Дата: 01.02.2013
Ответить


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

Den

Фотография
Дата: 01.02.2013
Ответить


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


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

Mikhail Sukhov

Фотография
Дата: 01.02.2013
Ответить


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


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

Добавить файлы через драг-н-дроп, , или вставить из буфера обмена.

loading
clippy