2013-06-03 2 views
1

Я пытаюсь найти источник утечки памяти из потока. Поток запускает синхронизированные события повторно, возвращая объект, защищенный потоком.Синхронизированное событие из потока - утечка памяти

я вызвать это событие в потоке путем вызова процедуры ...

procedure TDeskMonThread.DoOnImage(const ID: Integer; const R: TRect; 
    ABmp: TLockBmp); 
begin 
    FSyncOnImageID:= ID; 
    FSyncOnImageRect:= R; 
    FSyncOnImageBmp:= ABmp; 
    Synchronize(SYNC_OnImage); 
end; 

3 частных полей используются только для этой цели - временного хранения для использования в триггера событий. TLockBmp - это всего лишь обертка вокруг TBitmap с критической секцией, требующей блокировки и разблокировки.

Затем Синхронизировать называет эту процедуру:

procedure TDeskMonThread.SYNC_OnImage; 
begin 
    if Assigned(FOnImage) then //trigger event 
    FOnImage(FSyncOnImageID, FSyncOnImageRect, FSyncOnImageBmp); 
end; 

и это событие обрабатывается с помощью этой процедуры:

procedure TfrmMain.ThreadOnImage(const ID: Integer; const R: TRect; 
    ABmp: TLockBmp); 
var 
    B: TBitmap; 
begin 
    if ID = FCurMon then begin //Only draw if it's the current monitor 
    B:= ABmp.Lock; 
    try 
     FBmp.Assign(B); //Copy bitmap over 
    finally 
     ABmp.Unlock; //Hurry and unlock so thread can continue its work 
    end; 
    ResizeBitmap(FBmp, pbView.ClientWidth, pbView.ClientHeight, clBlack); 
    pbView.Canvas.Draw(0, 0, FBmp); //Draw to canvas 
    end; 
end; 

Теперь я сузили его до ResizeBitmap, потому что, когда я комментирую, что строка кода, я не получаю утечку памяти. Вот эта процедура: сообщение утечки

procedure ResizeBitmap(Bitmap: TBitmap; Width, Height: Integer; Background: TColor); 
var 
    R: TRect; 
    B: TBitmap; 
    X, Y: Integer; 
begin 
    if assigned(Bitmap) then begin 
    B:= TBitmap.Create; 
    try 
     if Bitmap.Width > Bitmap.Height then begin 
     R.Right:= Width; 
     R.Bottom:= ((Width * Bitmap.Height) div Bitmap.Width); 
     X:= 0; 
     Y:= (Height div 2) - (R.Bottom div 2); 
     end else begin 
     R.Right:= ((Height * Bitmap.Width) div Bitmap.Height); 
     R.Bottom:= Height; 
     X:= (Width div 2) - (R.Right div 2); 
     Y:= 0; 
     end; 
     R.Left:= 0; 
     R.Top:= 0; 
     B.PixelFormat:= Bitmap.PixelFormat; 
     B.Width:= Width; 
     B.Height:= Height; 
     B.Canvas.Brush.Color:= Background; 
     B.Canvas.FillRect(B.Canvas.ClipRect); 
     B.Canvas.StretchDraw(R, Bitmap); 
     Bitmap.Width:= Width; 
     Bitmap.Height:= Height; 
     Bitmap.Canvas.Brush.Color:= Background; 
     Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect); 
     Bitmap.Canvas.Draw(X, Y, B); 
    finally 
     B.Free; 
    end; 
    end; 
end; 

Память это то, что меня смущает:

enter image description here

x 3 варьируется в зависимости от того, как долго он был запущен, но не число итераций. Например, поток может повторить 20 итераций и показать x 3 или повторить 10 итераций и показать x 7, но я не могу даже найти шаблон количества утечек по сравнению с тем, сколько итераций. Кажется, это происходит в случайные моменты, а не на каждой итерации.

Итак, я пошел на отладку процедуры ResizeBitmap, но когда я запускаю ее сам, даже многократно и быстро, я никогда не получаю утечек памяти. Кажется, что это связано с многократным вызовом его из потока. Я знаю, что это создает/уничтожает экземпляр TBitmap, который, возможно, не самый лучший способ, но все же я получаю эту утечку памяти, когда она многократно вызывается из потока. Я предполагаю, что есть скрытое исключение (из ресурсов), которое никогда не вызывает исключения, и, таким образом, попадает в ловушку как утечка памяти.

Откуда могла произойти утечка памяти? Как я могу это предотвратить?

+0

Обратите внимание, что разблокировка растрового изображения ничего не делает, чтобы поток продолжал выполнять какую-либо работу. В потоке по-прежнему нужно ожидать возврата «Синхронизация», что не произойдет, пока обработчик события не закончит работу. –

+1

Вам нужна полная версия FastMM для получения трассировки стека распределения.Или даже лучше, обнаружение утечки на madExcept 4. –

+0

@Rob Правда, я действительно имел в виду, что он не остается заблокированным слишком долго - как только я его больше не буду нуждаюсь в нем, откройте его, чтобы что-то еще могло получить к нему (поскольку следующие две строки кода могут занимать немного времени). Это предполагает, однако, что есть еще больше потоков, которых нет, но для будущей реализации большего количества потоков я уверен, что он будет готов, если я намереваюсь это сделать. –

ответ

5

EOutOfResources не имеет собственного конструктора, поэтому постарайтесь установить условные точки останова в различных конструкторах для Exception, которые будут срабатывать только при self.ClassType = EOutOfResources. Затем вы найдете точку, в которой создаются объекты исключений, и вы можете использовать трассировку стека, чтобы выяснить, что происходит с этой точки.

Кроме того, проверка утечки в целом становится намного проще, если вы используете FullDebugMode. Вы захотите загрузить полную версию FastMM4 из SourceForge и перестроить свой проект с помощью FullDebugMode и включить ведение журнала. Затем вместо простого диалога утечки памяти вы получите файл с подробной отладочной информацией об утечке памяти, включая трассировки стека в момент создания.

Смежные вопросы