Утечка памяти при создании потока

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
Deimos
постоялец
Сообщения: 174
Зарегистрирован: 16.01.2010 23:31:30

Утечка памяти при создании потока

Сообщение Deimos »

Всем доброго...

Не могу разобраться (лыжи не едут)...

Пустой примитивный поток

Пустая форма и утечка памяти...

Поток:

Код: Выделить всё

unit dirmon;

{$mode ObjFPC}{$H+}

interface

uses Classes, Windows, SysUtils;

type

  { TChangeMonitor }

  TChangeMonitor = class(TThread)
    private
    public
      constructor Create(ASuspended: boolean);
      destructor destroy; override;
    protected
      procedure Execute; override;
  end;

implementation

constructor TChangeMonitor.Create(ASuspended: boolean);
begin
  inherited Create(ASuspended);
  FreeOnTerminate:=true;
end;

destructor TChangeMonitor.destroy;
begin
  inherited destroy;
end;

procedure TChangeMonitor.Execute;
begin

end;

end.
Форма:

Код: Выделить всё

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, dirmon;

type

  { TForm1 }

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
     tmp:TChangeMonitor;
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  tmp:=TChangeMonitor.Create(true);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  tmp.Terminate;
end;

end.

Heap:

E:\Code\LCommander\threadsTest\test.exe
Heap dump by heaptrc unit of E:\Code\LCommander\threadsTest\test.exe
940 memory blocks allocated : 1447336/1448112
938 memory blocks freed : 1447240/1448016
2 unfreed memory blocks : 96
True heap size : 1540096 (160 used in System startup)
True free heap : 1539392
Should be : 1539456
Call trace for block $00000000016AE690 size 24
$000000010001180F
$000000010001388E
$000000010001315F
$000000010004B990
$000000010004BC88
$0000000100034E6A Create, line 26 of dirmon.pas
$0000000100034DC7 FormCreate, line 34 of unit1.pas
$00000001000239A3 DOCREATE, line 922 of include/customform.inc
$000000010002180E AFTERCONSTRUCTION, line 77 of include/customform.inc
$00000001000299BF CREATE, line 3218 of include/customform.inc
$0000000100031C28 CREATEFORM, line 2243 of include/application.inc
$0000000100002CA0 $main, line 23 of test.lpr
$0000000100002CC6
$00000001000175C0
$0000000100002C2B
$00007FFC9487259D
Call trace for block $0000000001614AD0 size 72
$0000000100011729
$000000010000E188
$0000000100034E3A Create, line 25 of dirmon.pas
$0000000100034DC7 FormCreate, line 34 of unit1.pas
$00000001000239A3 DOCREATE, line 922 of include/customform.inc
$000000010002180E AFTERCONSTRUCTION, line 77 of include/customform.inc
$00000001000299BF CREATE, line 3218 of include/customform.inc
$0000000100031C28 CREATEFORM, line 2243 of include/application.inc
$0000000100002CA0 $main, line 23 of test.lpr
$0000000100002CC6
$00000001000175C0
$0000000100002C2B
$00007FFC9487259D
$00007FFC9614AF38
$0000000100002C2B
$00007FFC9487259D

WIN11_64 PRO
Lazarus 3.8 32/64
FPC 3.2.2
У вас нет необходимых прав для просмотра вложений в этом сообщении.
xchgeaxeax
постоялец
Сообщения: 198
Зарегистрирован: 11.05.2023 02:51:40

Сообщение xchgeaxeax »

Попробуйте так:

Код: Выделить всё

procedure TForm1.FormDestroy(Sender: TObject);
begin
  tmp.Terminate;
  FreeAndNil(tmp);
end;
Deimos
постоялец
Сообщения: 174
Зарегистрирован: 16.01.2010 23:31:30

Сообщение Deimos »

xchgeaxeax

он-жеж

Код: Выделить всё

FreeOnTerminate:=true; 
У вас нет необходимых прав для просмотра вложений в этом сообщении.
xchgeaxeax
постоялец
Сообщения: 198
Зарегистрирован: 11.05.2023 02:51:40

Сообщение xchgeaxeax »

Deimos писал(а):xchgeaxeax

он-жеж

Код: Выделить всё

FreeOnTerminate:=true; 
Так вы тред запустите

Добавлено спустя 29 минут 1 секунду:
Я так понял вы не понимаете что именно происходит в вашем коде.
В дополнительном потоке будет работать только этот код

Код: Выделить всё

procedure TChangeMonitor.Execute;
begin

end;
Но эта процедура пустая и поэтому тред сразу помрет. Зато останется ThreadID, ThreadHandle и ExitCodeThread

А вот что происходит в основном треде вашей программы (я просто соберу процедуры подряд)

Код: Выделить всё

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
     tmp:TChangeMonitor;
  public

  end;

// Это дефолтный класс формы, который вами был дополнен приватным полем tmp (этим полем владеет класс формы и время жизни должен контролировать именно он; здесь все верно)

procedure TForm1.FormCreate(Sender: TObject);
begin // Обработчик создания объекта TForm1 заодно создает объект tmp
  tmp:=TChangeMonitor.Create(true);
end;

constructor TChangeMonitor.Create(ASuspended: boolean {true из TForm1.FormCreate});
begin // Конструктор объекта треда (он выполняется в основном треде, а не создаваемом)
  inherited Create(ASuspended); // Вызов конструктора TThread.Create(true). Т.е. поток должен быть приостановлен после создания объекта его описания
  FreeOnTerminate:=true; // Вы выключаете автоматическое уничтожение объекта описания потока после завершения (выхода из процедуры Execute, а не сразу по TThread.Terminate)
// Это хорошо. Так форма сможет контролировать время жизни переменной tmp
end;
Но вот вы не запустили поток и реального системного объекта Thread не создано, который и будет этим самым тредом исполняющим Execute

После же нажатия на крестик у формы выполняется следующее

Код: Выделить всё

procedure TForm1.FormDestroy(Sender: TObject);
begin
  tmp.Terminate; // Вы переключаете состояние потока в Terminated и не дождавшись его окончания просто уничтожаете объект его описания. Так можно делать, но осторожно
// А вот проблема как раз тут в следующем: Нету реального системного Thread т.к. у вас в TForm1.FormCreate создан замороженный поток. Поэтому его нельзя уничтожить и отсюда ошибка хэндла
  FreeAndNil(tmp); // А вот эта команда нужна т.к. вы сделали FreeOnTerminate:=true; чтобы устранить утечку памяти в объекте tmp, о которой ваше сообщение из 1 поста
// После этого будет вызвана TChangeMonitor.destroy
end;

destructor TChangeMonitor.destroy;
begin
  inherited destroy; // Которая просто вызовет TThread.Destroy;
end;
Deimos
постоялец
Сообщения: 174
Зарегистрирован: 16.01.2010 23:31:30

Сообщение Deimos »

Признаю - мой косяк )
Ответить