Не освобождается память при уничтожении компонентов

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

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

Не освобождается память при уничтожении компонентов

Сообщение rayanAyar » 14.06.2011 13:25:00

Мне нужно в runtime создавать и уничтожать компоненты. Иногда в большом количестве. Проблема в том, что после уничтожения компонентов занимаемая ими память уже не освобождается.

Может быть я не правильно создаю/уничтожаю компоненты?

Или это особенности работы менеджера памяти FPC ? Если это менеджер памяти такой - может быть есть способ запустить "сборку мусора"?

В приведенном ниже примере:
- запуск приложения: 3472kB
- после создания компонентов: 10220kB
- после уничтожения компонентов: 9708kB

Как вернуть системе эти 6 мегабайт?

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

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton; //Показать использование памяти
    Button2: TButton; //Создать компоненты
    Button3: TButton; //Уничтожить компоненты
    Label1: TLabel;
    ScrollBox1: TScrollBox;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  sl: TStringList;
begin
  {$IFDEF UNIX}
  sl:= TStringList.Create;
  sl.LoadFromFile('/proc/self/status');
  sl.NameValueSeparator:= ':';
  Label1.Caption:= Trim(sl.Values['VmData']);
  sl.Free;
  sl:= nil;
  {$ENDIF}
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  ctrlChild: TEdit;
  lCntr: Longint;
begin
  ScrollBox1.AutoScroll:= False;
  for lCntr:= 1 to 1000 do
  begin
    ctrlChild:= TEdit.Create(ScrollBox1);
    ctrlChild.Name:= 'ctrl' + IntToStr(lCntr);
    ctrlChild.Top:= ctrlChild.Height * (lCntr - 1);
    ctrlChild.Text:= 'ctrl' + IntToStr(lCntr);
    ctrlChild.Parent:= ScrollBox1;
  end;
  ScrollBox1.AutoScroll:= True;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  lCntr: Longint;
begin
  ScrollBox1.AutoScroll:= False;
  for lCntr:= ScrollBox1.ComponentCount downto 1 do
  begin
    ScrollBox1.Components[lCntr - 1].Free;
  end;
  ScrollBox1.AutoScroll:= True;
end;

end.


Пробовал на Lazarus 0.9.30 GTK2, Debian/Ubuntu i386/amd64.
Аватара пользователя
rayanAyar
новенький
 
Сообщения: 42
Зарегистрирован: 06.01.2011 08:22:52
Откуда: Новоуральск

Re: Не освобождается память при уничтожении компонентов

Сообщение VirtUX » 14.06.2011 17:29:57

А если вместо
Код: Выделить всё
ScrollBox1.Components[lCntr - 1].Free;
написать
Код: Выделить всё
FreeAndNil(ScrollBox1.Components[lCntr - 1]);
?
Хотя здесь вряд-ли что-то изменится...
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Не освобождается память при уничтожении компонентов

Сообщение sign » 14.06.2011 17:45:03

windows XP.
Lazarus 0.9.30
FPC 2.4.2

Код: Выделить всё
Запуск: 8 164

Button2: 10 156   10 196   10 168   10 216   10 408   10 436
Button3:  9 372    9 412    9 408    9 484    9 480    4 476
sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Re: Не освобождается память при уничтожении компонентов

Сообщение rayanAyar » 14.06.2011 19:36:17

VirtUX писал(а):А если вместо
Код: Выделить всё
ScrollBox1.Components[lCntr - 1].Free;
написать
Код: Выделить всё
FreeAndNil(ScrollBox1.Components[lCntr - 1]);
?
Хотя здесь вряд-ли что-то изменится...

Пробовал - никакой разницы. Собственно и не должно её быть. FreeAndNil - это вызов Free и присваивание nil.

sign писал(а):
Код: Выделить всё
Запуск: 8 164

Button2: 10 156   10 196   10 168   10 216   10 408   10 436
Button3:  9 372    9 412    9 408    9 484    9 480    4 476

Круто :). "Миллиард китайцев попробовали пароль 12345 на доступ к сайту pentagon.gov, на половине попыток компьютер пентагона согласился."

А как вобще могло получиться меньше чем при старте?
Эти результаты повторяемые?
Аватара пользователя
rayanAyar
новенький
 
Сообщения: 42
Зарегистрирован: 06.01.2011 08:22:52
Откуда: Новоуральск

Re: Не освобождается память при уничтожении компонентов

Сообщение sign » 14.06.2011 20:17:26

В последней колонке опечатка, читать - 9 476
sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Re: Не освобождается память при уничтожении компонентов

Сообщение Odyssey » 14.06.2011 21:10:10

Чтобы найти утечку памяти, если она есть, можно воспользоваться heaptrc:
Код: Выделить всё
uses HeapTrc, ... // модуль должен быть первым в секции uses
...
begin
  SetHeapTraceOutput('heaptrc_log.txt');
  ...
end.

И после завершения программы в файле можно будет посмотреть список утечек.
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: Не освобождается память при уничтожении компонентов

Сообщение rayanAyar » 15.06.2011 06:32:53

Код: Выделить всё
Heap dump by heaptrc unit
38862 memory blocks allocated : 5033375/5114272
38862 memory blocks freed     : 5033375/5114272
0 unfreed memory blocks : 0
True heap size : 393216
True free heap : 393984
Should be : 393216

HeapTrc говорит, что "0 unfreed".
Аватара пользователя
rayanAyar
новенький
 
Сообщения: 42
Зарегистрирован: 06.01.2011 08:22:52
Откуда: Новоуральск

Re: Не освобождается память при уничтожении компонентов

Сообщение .wOvAN » 15.06.2011 11:48:25

Нажмите свернуть окно, затем обратно разверните. :)
.wOvAN
постоялец
 
Сообщения: 118
Зарегистрирован: 16.04.2010 06:36:12

Re: Не освобождается память при уничтожении компонентов

Сообщение rayanAyar » 15.06.2011 11:55:10

Никакой реакции на сворачивание/разворачивание.
Аватара пользователя
rayanAyar
новенький
 
Сообщения: 42
Зарегистрирован: 06.01.2011 08:22:52
Откуда: Новоуральск

Re: Не освобождается память при уничтожении компонентов

Сообщение Mr.Smart » 15.06.2011 12:03:20

.wOvAN Это в Виндас.

Добавлено спустя 1 минуту 35 секунд:
rayanAyar если так напрягает, что стандартный мнеджер памяти FPC не сразу отдаёт память (это кстати сделано для увеличения производительности) используйте другой, например cmem.
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Не освобождается память при уничтожении компонентов

Сообщение rayanAyar » 15.06.2011 12:21:52

Mr.Smart писал(а):rayanAyar если так напрягает, что стандартный мнеджер памяти FPC не сразу отдаёт память (это кстати сделано для увеличения производительности)

Что значит "не сразу"? Через какое время он вернет память системе?
Меня бы это не напрягало, если бы со временем память возвращалась. Но она не освобождается. Даже через несколько часов. Может быть есть какая-то возможность управлять менеджером памяти?


Mr.Smart писал(а):rayanAyar используйте другой, например cmem.

Пробовал - такая же ситуация.
Аватара пользователя
rayanAyar
новенький
 
Сообщения: 42
Зарегистрирован: 06.01.2011 08:22:52
Откуда: Новоуральск

Re: Не освобождается память при уничтожении компонентов

Сообщение Odyssey » 15.06.2011 12:30:15

rayanAyar писал(а):Может быть есть какая-то возможность управлять менеджером памяти?

Точно можно создать свой менеджер. Насчёт управления существующим, наверное, смогут ответить только разработчики в рассылке.
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: Не освобождается память при уничтожении компонентов

Сообщение Mr.Smart » 15.06.2011 12:52:03

rayanAyar писал(а):
Mr.Smart писал(а):rayanAyar используйте другой, например cmem.

Пробовал - такая же ситуация.

cmem использует непосредственно функции выделения и освобождение памяти из библиотеке libc и сам распределением блоков не занимается. Т.ч. возможно ошибки у вас в коде.
Как вы определяете какой объём памяти занимает в данный момент ваша программа?
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Не освобождается память при уничтожении компонентов

Сообщение rayanAyar » 15.06.2011 13:45:53

Mr.Smart писал(а):Как вы определяете какой объём памяти занимает в данный момент ваша программа?

Стандартными утилитами: htop, ps, Системный монитор. Все эти утилиты берут информацию об использовании памяти из /proc. От туда же я читаю эту информацию в программе.

Самое интересное, что после уничтожения всех компонентов heap освобождается до исходного состояния. Но при этом "система говорит", что сегмент данных приложения гораздо больше heap.

Вот например:
запуск приложения
CurrHeapSize: 2260992; CurrHeapUsed: 561728; CurrHeapFree: 1699264; RSS: 11724 kB; DataSegment: 3588 kB;
создание 5000 компонентов (Button2)
CurrHeapSize: 9011200; CurrHeapUsed: 8091744; CurrHeapFree: 919456; RSS: 49620 kB; DataSegment: 40812 kB;
уничтожение всех созданных компонентов (Button3)
CurrHeapSize: 2654208; CurrHeapUsed: 560352; CurrHeapFree: 2093856; RSS: 43240 kB; DataSegment: 34216 kB;

Итого 30МБ приложение не вернуло системе.

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

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton; //Показать использование памяти
    Button2: TButton; //Создать компоненты
    Button3: TButton; //Уничтожить компоненты
    Edit1: TEdit; //Количество создаваемых компонентов
    Memo1: TMemo;
    ScrollBox1: TScrollBox;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  slProc: TStringList;
  FPCHeapStatus: TFPCHeapStatus;
  sTmp: String;
begin
  sTmp:= '';

  FPCHeapStatus:= GetFPCHeapStatus;
  sTmp:= sTmp + 'CurrHeapSize: ' + IntToStr(FPCHeapStatus.CurrHeapSize) + '; ';
  sTmp:= sTmp + 'CurrHeapUsed: ' + IntToStr(FPCHeapStatus.CurrHeapUsed) + '; ';
  sTmp:= sTmp + 'CurrHeapFree: ' + IntToStr(FPCHeapStatus.CurrHeapFree) + '; ';

  {$IFDEF UNIX}
  slProc:= TStringList.Create;
  slProc.LoadFromFile('/proc/self/status');
  slProc.NameValueSeparator:= ':';
  sTmp:= sTmp + 'RSS: ' + Trim(slProc.Values['VmRSS']) + '; ';
  sTmp:= sTmp + 'DataSegment: ' + Trim(slProc.Values['VmData']) + '; ';
  slProc.Free;
  slProc:= nil;
  {$ENDIF}

  Memo1.Lines.Add(sTmp);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  ctrlChild: TEdit;
  lCntr: Longint;
begin
  ScrollBox1.AutoScroll:= False;
  for lCntr:= 1 to StrToInt64Def(Edit1.Text, 1000) do
  begin
    ctrlChild:= TEdit.Create(ScrollBox1);
    ctrlChild.Name:= 'ctrl' + IntToStr(lCntr);
    ctrlChild.Top:= ctrlChild.Height * (lCntr - 1);
    ctrlChild.Text:= 'ctrl' + IntToStr(lCntr);
    ctrlChild.Parent:= ScrollBox1;
  end;
  ScrollBox1.AutoScroll:= True;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  ctrlChild: TEdit;
  lCntr: Longint;
begin
  ScrollBox1.AutoScroll:= False;
  for lCntr:= ScrollBox1.ComponentCount downto 1 do
  begin
    ctrlChild:= TEdit(ScrollBox1.Components[lCntr - 1]);
    ctrlChild.Free;
  end;
  ScrollBox1.AutoScroll:= True;
end;

end.
Аватара пользователя
rayanAyar
новенький
 
Сообщения: 42
Зарегистрирован: 06.01.2011 08:22:52
Откуда: Новоуральск


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 42

Рейтинг@Mail.ru