Есть ли, помимо поиска утечек памяти, еще одна ситуация, когда я должен освобождать все объекты при уничтожении приложения? - PullRequest
8 голосов
/ 27 марта 2012

Предположим, что приложение с некоторыми формами и только один модуль данных создается при запуске.В событии DM1.OnCreate создается TStringList для использования во время выполнения.Мы знаем, что, когда приложение завершается, все вещи будут уничтожены, и память будет автоматически освобождена.Освобождение чего-либо может занять некоторое время, и поэтому не всегда рекомендуется беспокоиться об утечках памяти при завершении работы.См., Например, этот ответ от Барри Келли или этот пост от Раймонда Чена.

Помимо этого, FastMM сообщает об утечке памяти, если я не добавлю TStringList.Freeдо DM1.OnDestroy.Это оказывается проблемой при поиске любых других утечек памяти, о которых я должен действительно беспокоиться.

Поэтому в основном я спрашиваю, нужно ли / почему / когда мне освобождать экземпляры объектов, которые будутбыть освобожденным приложением или ОС (Windows в данном конкретном случае).Есть ли другой допустимый случай, который не применяется при поиске утечек памяти?

ПРИМЕЧАНИЕ : В этом конкретном случае модуль данных не создается или воссоздается повторно.Не будет никакой утечки памяти вообще, кроме одной.Источник данных модуля данных:

unit UDM1;

interface

uses SysUtils, Classes, ...;

type
  TDM1 = class(TDataModule)
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
    procedure DoStuffWithStringList1(Sender: TObject);
  private
    internalStL: TStringList;
  end;

var
  DM1: TDM1;

implementation

procedure TDMInterfacePAFECF.DataModuleCreate(Sender: TObject);
begin
  internalStL := TStringList.Create();
end;

procedure TDMInterfacePAFECF.DataModuleDestroy(Sender: TObject);
begin
  internalStL.Free; //<-- IS THIS NECESSARY OR ADVISED?
end;

procedure DoStuffWithStringList(Sender: TObject);
begin
  //Place some code using internalStL here...

end;

Ответы [ 5 ]

7 голосов
/ 27 марта 2012

По той же причине я настоятельно рекомендую (преуменьшение) не оставлять подсказку или предупреждение компилятора в проекте, убирайте за собой и НЕ ОСТАВЛЯЙТЕ УТВЕРЖДЕННОЙ ПАМЯТЬЮ ПАМЯТИ!
КОГДА-ЛИБО!

Теперь это не обязательно означает, что вам нужно освободить все в деструкторе вашего DataModule, если у вас есть веские основания не делать этого, но в этом случае вам необходимо зарегистрировать утечку памяти , чтобы об этом не сообщалось.(И поместите там очень заметный комментарий, чтобы оправдать и объяснить, почему)

Но учтите тот факт, что вы можете покинуть этот проект и через год, кто-то другой поддерживает его и предъявляет новые бизнес-требования для создания несколькихDataModules ... Скорее всего, если они недостаточно хорошо знают внутреннюю часть вашего кода, они будут доверять вашему коду, чтобы он был чистым, и проблемы, вероятно, последуют.

Поэтому я настоятельно рекомендую не освобождать, еслив очень особенном, ожидаемом и задокументированном случае ...

PS: Я видел это, и мне приходилось так часто стирать память, стекающую повсюду, что я даже проводил несколько сеансов CodeRage по борьбе с утечками памяти ...

Updayte: Вот ссылка для загрузки этой сессии CodeRage ...

7 голосов
/ 27 марта 2012

Мой ответ можно считать философским, но главная причина в том, что любое действие (или его отсутствие) имеет последствия.Я подумал о вашем примере и, возможно, других примерах, и я вижу одну хорошую причину, чтобы освободить объект.Каждый раз, когда я думаю, что могу игнорировать освобождение объекта, увеличивается вероятность не делать этого в другой, возможно, более серьезной ситуации.Другим примером является привычка делать «попытайся окончить конец» везде, где что-то выделено или освобождено.Меня не волнует освобождение в случае исключения, но эта привычка помогает мне избежать утечки

5 голосов
/ 27 марта 2012

Используйте RegisterExpectedMemoryLeak для преднамеренных утечек памяти. У подпрограммы есть несколько перегруженных версий, из которых можно бороться с классом объекта:

begin
  RegisterExpectedMemoryLeak(TStringList);
  FStringList := TStringList.Create;
  ...

или лучше, зарегистрируйте сам указатель:

begin
  FStringList := TStringList.Create;
  RegisterExpectedMemoryLeak(FStringList);
  ...

В этом случае неожиданные утечки памяти будут отображаться нормально и не могут быть перепутаны с этим конкретным списком строк.

4 голосов
/ 27 марта 2012

Позвольте мне ответить, задав вам вопрос.

Можно ли с уверенностью сказать, что жизненный цикл модуля данных будет всегда привязан к времени жизни приложения или что вам никогда не потребуется создавать дополнительные экземпляры этого приложения?

Если вы ответите «да», не стесняйтесь игнорировать стандартные методы управления памятью.

Если вы отвечаете «нет», вам следует убедиться, что объект убирается за собой.

2 голосов
/ 28 марта 2012

Вещи выполняются, когда вы освобождаете объект, возможно, больше, чем только освобождение памяти.

Вспоминается объект базы данных, который выполняет транзакции и завершает все запущенные транзакции в ondestroy.

Если вы не позвоните бесплатно, ondestroy не будет уволен, и вы можете получить заблокированные столы.

...