Всем добрый вечер!
В текущем проекте я испытываю довольно тревожную утечку памяти, которую я просто не могу исправить.
Я оставил приложение работать на ночь при стандартном использовании, и когда я проснулся через 8 часов, он занимал ~ 750 МБ памяти, тогда как начался с ~ 50 МБ. Диспетчер задач Windows не подходит для проверки утечек, кроме как для определения того, что она существует.
Я уже устранил несколько других утечек памяти, основная из которых связана с TGlowEffect
Firemonkeys. Он не обнаруживается ReportLeaksOnShutdown
, но использование памяти становится чрезмерным для динамически изменяемого объекта (например, при повороте или изменении масштаба).
Я отследил это до таймера (и его отключение полностью останавливает утечку), и мне нужна помощь в его устранении, если это возможно.
Описание: этот код использует функцию Firemonkey MakeScreenshot
для сохранения внешнего вида TPanel (SigPanel)
в TMemoryStream
. Эти данные потока затем загружаются на удаленный FTP-сервер с использованием стандартного кода (см. Ниже). Внутри SigPanel
есть 4 TLabel
детей, 1 TRectangle
ребенок и 6 TImage
детей.
Примечания: CfId
- это глобальная строка, которая создается на основе случайного extended
значения с плавающей запятой, которое затем хешируется вместе с DateTime в формате yyyymmdd_hhnnsszzz
. Эта генерация выполняется при создании формы и повторяется до тех пор, пока не получит действительный CfId
(т.е. не будет содержать символы, недопустимые для использования в именах файлов Windows). Как только он получает действительный CfId
, он больше не запускается (поскольку мне больше не нужно генерировать новый идентификатор). Это позволяет мне почти полностью исключить возможность дублирования CfId
.
Код в таймере следующий:
var
i : Integer;
SigStream : TMemoryStream;
begin
SigStream := TMemoryStream.Create;
SigPanel.MakeScreenshot.SaveToStream(SigStream);
SigPanel.MakeScreenshot.Free;
if VT2SigUp.Connected then
begin
VT2SigUp.Put(SigStream,'Sig_'+CfId+'.png',False);
end else
begin
VT2SigUp.Connect;
VT2SigUp.Put(SigStream,'Sig_'+CfId+'.png',False);
end;
SigStream.Free;
end;
Когда таймер НЕ запущен, код работает полностью без утечек, а ReportMemoryLeaksOnShutdown
НЕ генерирует сообщение. Когда таймер включен и мне разрешено «работать» хотя бы один раз, я получаю много утечек, которые тем больше, чем больше таймер запускается. Сообщенные утечки следующие:
Small Block Leaks
1 - 12 Bytes: Unknown x 1
13 - 20 Bytes: TList x 5, Unknown x 1
21 - 28 Bytes: TFont x 2, TGradientPoint x 8, TGradientPoints x 4, Unknown x 4
29 - 36 Bytes: TObjectList<FMX.Types.TCanvasSaveState> x 1, TBrushBitmap x 4,
TBrushGrab x 4, TPosition x 24, TGradient x 4, UnicodeString x1
37 - 44 Bytes: TBrushResource x 4
53 - 60 Bytes: TBrush x 4
61 - 68 Bytes: TBitmap x 5
69 - 76 Bytes: TD2DCanvasSaveState x 1
205 - 220 Bytes: TCanvasD2D x 1
Sizes of Medium and Large Block Leaks
200236
По мере запуска таймера эти значения умножаются n раз (n - количество запусков таймера). Средний и большой блоки имеют значение 200236 n (например, если таймер сработал 3 раза, это 200236, 200236, 200326).
Интересно, что если я удалю код, связанный с MakeScreenshot
, утечки больше не будет, а использование памяти останется на несколько нормальном уровне. Помимо обычного использования памяти, нет ничего необычного и об утечках не сообщается. Я пробовал несколько образцов кода, как с сохранением в поток, так и с загрузкой оттуда, или с сохранением в поток> Файл, а затем с загрузкой файла, но, похоже, в самой функции есть утечка. Я даже добавил MakeScreenshot.Free
, как только обнаружил здесь утечку, но я просто не могу ее заткнуть, и, конечно же, я использовал try..finally
в одном из «тестовых прогонов» кода.
Я даже запустил код с GDI + в качестве типа холста, и там произошла такая же утечка (с единственным изменением, что утечка D2D вместо этого ссылается на GDI +).
Я был бы очень признателен за любые исследования или заметки, которые есть у кого-либо по этому поводу, и, более того, за решение проблемы.
ReportMemoryLeaksOnShutdown := True;
в инициализации вашего приложения должна помочь, чтобы показать вам, что протекает ... - person Jerry Dodge   schedule 28.05.2012Result
вFMX.Types.MakeScreenshot
на самом деле не освобожден. Они просто звонятResult.Canvas.EndScene
и никогда не освобождают его! @JerryDodge Это то, что я побежал выяснить, что именно просачивалось, поскольку без этого я бы не смог получить точный список :) - person Scott P   schedule 28.05.2012