Delphi/FPC: утекает память в IntToHex

yolki

проверено на D7/D2007 (утекает 20 байт на вызов)
проверено в FPC 2.2.0 (утекает 16 байт на вызов)

{$APPTYPE CONSOLE}

uses
SysUtils;

type TIntArray = array of integer;

var
hs: THeapStatus;
a: TIntArray;

begin

hs:=GetHeapStatus;
writeln(hs.TotalAllocated );
SetLength(a,200);
WriteLn(IntToHex(Integer(Pointer(a8;
hs:=GetHeapStatus;
writeln(hs.TotalAllocated );
SetLength(a,0);
WriteLn(IntToHex(Integer(Pointer(a8;
hs:=GetHeapStatus;
writeln(hs.TotalAllocated );
writeln('ales');

end.

Кто-нибудь может что-то прокомментировать?

NataNata

а fastmm из 2k7 что говорит?

yolki

сорри, я 2007 в глаза не видел ни разу, поставил триал чтобы проверить эти лики.
названия обнадёживающие. как этим FastMM пользоваться?

NataNata

fastmm - сторонний менеджер памяти, который был в D2006 сделан по умолчанию заместо предыдущего (который в D7). менеджер умеет ловить leaks, так что если ты включишь какую-то там опцию (fulldebugmode и еще что-то то прога каждый раз при завершении будет плеваться о том, сколько памяти утекло, уточняя какие переменные именно и какие процедуры "глюканули" (последняя версия sourceforge.net/projects/fastmm/, на D7 работает). качни, поставь и проверь. если не будет плеваться, значит все ок
кроме того, у этого fastmm есть такой прикол, что он может память явно (т.е. через virtualfree) не освобождать сразу после вызова деструктора \ freemem-а. а может как-то ее по-хитрому кэшировать. у меня была такая ситуация: в многопоточном приложении в подгружаемой DLL выделялось в нескольких потоках по двумерному массиву по 400 мегабайт каждый (потом с массивами была работа НО при освобождении массивов прога память не освобождала и диспетчер памяти показывал, что прога выделила сотни мегабайт.
з.ы. переходи на D2007

SPARTAK3959

Оборачиваете все в цикл и повторяете 100-10000 раз. У меня количество памяти при этом не возрастает - а значит утечки нет. Если вас интересует почему разница не в 400 байт - так не забывайте про структуры кучи, выравнивание в ней, резерв массива и.т.д.

yolki

тут ты не прав.
сделай не циклом, а линейный участок на 100 таких действий. тебя кое-что удивит ;)

yolki

в общем, шаманство с массивами можно выкинуть.
делаем так:

WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;
WriteLn(IntToHex(Integer(Pointer(a8;

Если брать FastMM, то FastGetHEapStatus тоже показывает увеличение TotalAllocated на каждый вызов IntToHex на 20байт.
Цикл такого эффекта не даёт. независимо от длины цикла утекает ровно 20 байт.
если в цикле два раза IntToHex, то утечёт 40.
однако после завершения работы Fast отчёта не даёт.

SPARTAK3959

Сделал - независимо от числа inttohex'ов разница в 32 байта. Впрочем, даже если бы она росла, это не было бы утечкой - мало ли какие паскаль временные переменные создает. Вот если память растет в цикле - это утечка. Так что пока у вас нет такого примера - не надо будоражить общественность.
Я уже не говорю о том, что исходники IntToHex можно и посмотреть. В FPC 2.2.0 и 2.2.1 она выглядит так:
{   IntToHex returns a string representing the hexadecimal value of Value   }

const
Heigits: array[0..15] of char = '0123456789ABCDEF';

function IntToHex(Value: integer; Digits: integer): string;
var i: integer;
begin
SetLength(result, digits);
for i := 0 to digits - 1 do
begin
result[digits - i] := Heigits[value and 15];
value := value shr 4;
end ;
while value <> 0 do begin
result := Heigits[value and 15] + result;
value := value shr 4;
end;
end ;

Andbar

Я уже не говорю о том, что исходники IntToHex можно и посмотреть.
В D7 она реализована на асме.
Кстати, интересно вот что: под D6 такой-же эффект тоже сохранялся?

SPARTAK3959

А асм надо знать!

yolki

ага,

lea eсx, [ebp-$04]

вот это что означает?
такая инструкция предшествует непосредственно запихиванию аргументов в регистры и вызову IntToHex

Chupa

> вот это что означает?
ecx=ebp-4 всего лишь

Elina74

ecx=ebp-4 всего лишь
по-моему, скобочки [ebp-4] означают взятие содержимого по адресу ebp-4

Chupa

а lea по-твоему что означает?

ppplva

А lea - взятие адреса.
ecx = &*(ebp-4)

Andbar

Сборка с debug DCUs и выполнение с установкой брейкпоинтов на SysGetMem, SysFreeMem и SysReallocMem показала что в inttohex выделяется память под строку, которая после выполнения writeln не освобождается. Тоже самое, в общем-то, происходит и с inttostr, кстати. Но эти строки освобождаются перед выходом из текущей функции/процедуры, для подтверждения этого достаточно выделить большую часть приведённого кода в отдельную функцию и проверить перед её вызовом и после количество выделенной памяти.
Короче, нечего бить тревогу: никаких утечек здесь нет и быть не может.
ps: у меня D7, если что..
pps: и чем это я на работе занимаюсь?

NataNata

если fastmm не ругается (при учете включенной проверки на leakи значит все в порядке.

buka

Добро пожаловать в мир подсчёта ссылок, Вася

SPARTAK3959

Ну я-то и так все на java пишу, используя паскаль и асм только для задач (в основном переборных где нужна максимальная производительность.
Оставить комментарий
Имя или ник:
Комментарий: