Форум: "Основная";
Текущий архив: 2002.08.22;
Скачать: [xml.tar.bz2];
ВнизОсвобождение памяти Найти похожие ветки
← →
SashaK (2002-08-13 14:05) [0]У меня есть массив из записей (Record). Запись имеет строковые поля. Когда я присваиваю в строковое поле значение, очевидно, выделяется память и туда пишется строка. Будет ли при удалении массива освобождаться память, выделенная под строки ?
← →
Skier (2002-08-13 14:12) [1]>SashaK
для "статичного" (т.е. если ты под него сам не выделяешь память, а это делает Delphi) массива - да, т.к. Delphi имеет
механизм подсчёта ссылок на строку - если кол-во ссылок
становится равным 0, то строка освобождается...
В случае динамического выделения памяти - могут быть
варианты...
← →
SashaK (2002-08-13 14:38) [2]Память выделяется динамически. Массив записей я реализовал в классе, который обеспечивает выделение памяти под нужное количество записей. Записи могут любыми, при создании массива просто передается размер SizeOf(MyRecord).
← →
Digitman (2002-08-13 15:52) [3]каков конкретный тип строковых полей записи ?
← →
kull (2002-08-13 16:11) [4]...никаких вариантов - освобождается.
← →
Digitman (2002-08-13 16:21) [5]>kull
Неверно. Нижеследующий вариант
type
prec = ^trec;
trec = record
s: string;
end;
var
rec: prec;
s1: string;
..
s1:= "XXX";
new(rec);
rec.s := s1;
dispose(rec);
дает 100%-ю утечку
← →
Ученик (2002-08-13 16:27) [6]>Digitman
В Delphi 6 память освобождается Dispose
← →
kull (2002-08-13 16:42) [7]
> Digitman © (13.08.02 16:21)
Неверно. Как ты определил утечку?
Никакой утечки в этом примере нет, даже если сделать
SetLength(s1,1000).
Проверено Memory Sleuth 2.
← →
Digitman (2002-08-13 16:46) [8]>Ученик
С какой это стати ? Менеджер памяти, выполняющий Dispose() для блока памяти, отведенной ранее под структуру rec вызовом New(), ничего не знает о ее содержимом - менеджеру передается лишь указатель на некий блок памяти, который, в свою очередь содержит не просто какие-то статические данные в виде 4-байтного поля TRec.s, а 4 байта как указатель на динамическую строковую структуру. Память под эта самую строковую структуру была выделена неявным вызовом SysGetMem() в контексте исполнения строки rec.s := s1.
Приводи контраргументы и убеди меня в моей ошибке.
← →
Ученик (2002-08-13 16:47) [9]>Digitman © (13.08.02 16:46)
Пройдитесь в отладчике при Dispose
← →
Skier (2002-08-13 16:48) [10]>Digitman
Извините, Мастер, но Вы не правы Dispose освободит
и строку...
← →
Digitman (2002-08-13 16:50) [11]>kull
У меня - Д5.5
Просто отртрассировал этот код в окне CPU - нет ни одного SysFreeMem(), соответствующего предыдущему SysGetMem() для строкового поля при операции присвоения.
То же самое, если угодно, можно увидеть и в system.pas/sysutils.pas
← →
Ученик (2002-08-13 16:51) [12]>Digitman © (13.08.02 16:46)
Или проще по исходникам System.pas
← →
Ученик (2002-08-13 16:53) [13]procedure _Dispose{ p: Pointer; typeInfo: Pointer};
asm
{ -> EAX Pointer to object to be disposed }
{ EDX Pointer to type info }
PUSH EAX
CALL _Finalize
POP EAX
CALL _FreeMem
end;
procedure _Finalize{ p: Pointer; typeInfo: Pointer};
asm
MOV ECX,1
JMP _FinalizeArray
end;
procedure _FinalizeArray{ p: Pointer; typeInfo: Pointer; elemCount: Longint};
asm
{ -> EAX pointer to data to be finalized }
{ EDX pointer to type info describing data }
{ ECX number of elements of that type }
CMP ECX, 0 { no array -> nop }
JE @@zerolength
....
← →
Ученик (2002-08-13 16:53) [14]Это было из Delphi 5.0
← →
DiamondShark (2002-08-13 17:00) [15]Эх, господа теоретики!
Ну вы хоть перед тем как посты слать, проверьте, что пишите!
> Digitman © (13.08.02 16:21)
> >kull
>
> Неверно. Нижеследующий вариант
> <...>
> дает 100%-ю утечку
Что по вашему выдаст этот код
type
TRec = record
a: integer;
s: string;
end;
PRec = ^TRec;
var
R: PRec;
H: THeapStatus;
f1, f2: cardinal;
S1: string;
begin
S1 := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
H := GetHeapStatus;
f1 := H.TotalFree;
New(R);
R.s := S1;
Dispose(R);
H := GetHeapStatus;
f2 := H.TotalFree;
ShowMessageFmt("%d, %d", [F1, F2]);
end;
Или в CPU потрассируйте, убедитесь в вызове Finalize
Dispose работает корректно, так как учитывает тип.
А вот FreeMem даст утечку.
> SashaK (13.08.02 14:38)
Тогда придется вызывать Finalize с приведением типов.
пример:
type
TRec = record
a: integer;
s: string;
end;
TBuffer = array[0..0] of TRec;
PBuffer = ^TBuffer;
...
var
ByteSize: cardinal;
Buffer: pointer;
begin
ByteSize := GetNeededBufferSize;
GetMem(Buffer, ByteSize);
FillChar(Buffer^, ByteSize, 0); //Желательно
...
// какие-то действия, в том числе
PBuffer(Buffer)[i].s := "zzzzzzzzzzzzzzzzzzzzzzzzz";
...
Finalize(TRec(Buffer^), ElementCount); //Явный тип !!!
FreeMem(Buffer, ByteSize);
// теперь все чисто
end;
← →
DiamondShark (2002-08-13 17:04) [16]А Ученик прав.
Dispose учитывает неявный параметр -- тип переменной.
На стадии компиляции, естественно.
← →
kull (2002-08-13 17:04) [17]2 Digitman
Я конечно понимаю что вы - иастер, но зачем такие сложности?
Трассировка, изучение исходного кода.
Все проверяется простым виндовским системным монитором.
1. берем ваш пример и добавляем SetLength:
procedure TForm1.Button1Click(Sender: TObject);
type
prec = ^trec;
trec = record
s: string;
end;
var
rec: prec;
s1: string;
begin
SetLength(s1,1000000);
new(rec);
rec.s := s1;
dispose(rec);
end;
2. Запускаем системный монитор и при нажатии на Button1 не видим никакого изменения в объеме памяти.
если же dispose убрать, то изменение будет заметно не вооруженным глазом.
Сомневаюсь что в D5 Borland мог так налажать...
← →
kull (2002-08-13 17:07) [18]Нет, народ, вы меня просто удивляете - трассировка, CPU, ...
На фига все это нужно?
Любой ламер может проверить этот код на утечку обыкновенными стандартными средствами....
← →
Digitman (2002-08-13 17:08) [19]Приношу извинения. Действительно, в этом примере утечки не будет - компилятор вставляет неявный код LStrClr в FinalizeArray(). Проглядел, проскачив мимо Finalize().
Ок. Вот еще вариант :
type
prec = ^trec;
trec = record
s: PChar; // чем не вариант строкового типа ?
end;
var
rec: prec;
..
s1:= "XXX";
new(rec);
rec.s := SysGetMem(..);
strcopy(rec.s, ...);
dispose(rec);
вот и утечка ! а ведь - тоже вариант
← →
Skier (2002-08-13 17:09) [20]Ребята, мы тут спорим, а автор-то - молчит :)))
← →
DiamondShark (2002-08-13 17:09) [21]
> kull © (13.08.02 17:04)
Системный монитор -- плохой помошник.
Менеджер памяти Дельфи выделяет большой непрерывный кусок для кучи и уже в нем сам себе на уме распределяет строки и объекты.
Только когда этот кусок закончится, системный монитор покажет большой скачок в выделенной памяти -- дельфевый менеджер вышел на охоту.
← →
Digitman (2002-08-13 17:12) [22]>kull
Все то, что я знаю (если я чего-то знаю), дает мне "чистый" вообще и машкод в окне CPU в частности. Никакими сторонними средствами я никогда не пользовался, не пользуюсь и пользоваться не намерен - доверяю только Борланду и своей голове.
← →
kull (2002-08-13 17:13) [23]
>
> Digitman © (13.08.02 17:08)
Ну нет, это не вариант, PChar это не string.
Сам выделяешь сам и освобождай, здесь за тебя Delphi ничего не сделает. Это все равно что ^Integer.
← →
DiamondShark (2002-08-13 17:16) [24]
> Digitman © (13.08.02 17:08)
А еще в старом варианте можно предложить заменить описание
TRec = record
S: DWORD;
end;
и писать
string(Rec.S) := "sljkdflsjdlfjk";
Тоже гарантированная утечка ;)
А еще можно просто предложить на фиг убрать Dispose. И радостно так зубоскалить: "Утечка! Утечка!"
Зачем передергивать и примысливать ? ИМХО не достойно звания мастера. Сели в лужу, так обтекайте молча.
← →
kull (2002-08-13 17:21) [25]
> Все то, что я знаю (если я чего-то знаю), дает мне "чистый"
> вообще и машкод в окне CPU в частности. Никакими сторонними
> средствами я никогда не пользовался, не пользуюсь и пользоваться
> не намерен - доверяю только Борланду и своей голове.
Ну это ты зря - система то от Microsoft, так что это не стороннее средство...
И потом зачем расчитывать окружающую температуру по сложным формулам, когда есть термометр.
> Системный монитор -- плохой помошник.
>
> Менеджер памяти Дельфи выделяет большой непрерывный кусок
> для кучи и уже в нем сам себе на уме распределяет строки
> и объекты.
Я привык доверять не только борланду но и своим глазам.
В примере я выделил память для строки длинной 1000000.
Так вот с dispose монитор ничего не показал, а без dispose - видно, что память жрется. Ну и причем дельфовский менеджер?
Да даже если память выделяется блоками - никакой утечки все равно нет.
← →
Ученик (2002-08-13 17:22) [26]>DiamondShark © (13.08.02 17:16)
Зря Вы так, грубо это
← →
kull (2002-08-13 17:39) [27]
> Ученик © (13.08.02 17:22)
Выходит дед из немецкого штаба:
"Да, с коровой нае...али, да и с партизанами как-то некрасиво получилось..."
← →
DiamondShark (2002-08-13 17:39) [28]
> DiamondShark © (13.08.02 17:16)
Мои извинения. Действительно очень грубо.
> kull © (13.08.02 17:21)
1000000 -- слишком много. Дельфевый менеджер отбирает у системы минимум по 1 странице (4к байт) за раз.
Строки обычно короткие (к примеру на этой странице в строке умещается примерно 100 символов), так что иногда тестируя программу на приближенных к реальным даннах даже за несколько итераций не обнаружить утечку.
Конечно, на экстремальных тестах все сразу заметно.
← →
Digitman (2002-08-13 17:59) [29]>kull
>>Ну это ты зря ...
Позволь уж мне самому судить, зря или не зря, ok ?
>DiamondShark
Смею заметить, что я не отстаиваю "до упора" ошибочное мнение, каким бы устойчивым оно ни было до момента Х. И всегда готов публично признать свою ошибку, если она действительно имеет место быть. Тем более - как результат серьезных и детальных контраргументов, каковые и представил незамедлительно уважаемый <Ученик> (не в пример тебе). И это - абсолютно нормально. Истина рождается только так.
P.S.
Твои "доводы" я тоже учту, сударь. На будущее. При потенциально возможных дискуссиях с твоим участием.
← →
kull (2002-08-13 18:12) [30]
> Digitman © (13.08.02 17:59)
Вот как ты можешь доверять Borland, после твоего же заявления, о том, что он не освобождает память после использования строк.
> Смею заметить, что я не отстаиваю "до упора" ошибочное мнение,
> каким бы устойчивым оно ни было до момента Х. И всегда готов
> публично признать свою ошибку, если она действительно имеет
> место быть. Тем более - как результат серьезных и детальных
> контраргументов, каковые и представил незамедлительно уважаемый
> <Ученик> (не в пример тебе). И это - абсолютно нормально.
> Истина рождается только так.
Да ладно-ладно, ну промах допустил, ну с кем не бывает. Зачем оправдываться?
К чему речи одетальных контраргументах?
И на солнце бывают пятна!
Просто даже без детального разбора кода, ясно, что было бы смешно, если бы память не освобождалась там где она автоматически выделялась.
← →
DiamondShark (2002-08-13 18:14) [31]
> Digitman © (13.08.02 17:59)
Смею заметить, что отстаивание мнений (каких бы то ни было) не является основной целью выступления здесь. Основная цель -- корректный ответ на поставленный вопрос, и рекомендации к действиям, что было незамедлительно представлено DiamondShark © (13.08.02 17:00) (не в пример тебе).
Это учтите, сударь. На будущее.
PS
А на брудершафт мы, помнится, не пили. Так что в будущих дискуссиях, пожалуйста, на "вы".
← →
kull (2002-08-13 18:17) [32]Да ладно, народ, вы че?
Миру - мир!
← →
SashaK (2002-08-13 18:27) [33]Прошу прощения, не мог участвовать в форуме.
Освобождаю память через FreeMem. Насколько я понял, это приведет к утечке памяти, поэтому освобождать строку нужно руками.
← →
Skier (2002-08-13 18:30) [34]>SashaK
Освобождай через Dispose и будут тебе счастье... :)
← →
DiamondShark (2002-08-13 18:34) [35]
> SashaK (13.08.02 18:27)
> Прошу прощения, не мог участвовать в форуме.
Вы не много потеряли ;)
> Освобождаю память через FreeMem. Насколько я понял, это
> приведет к утечке памяти, поэтому освобождать строку нужно
> руками.
Да. Используя Finalize сразу для всего массива
см. DiamondShark © (13.08.02 17:00)
← →
Digitman (2002-08-13 18:39) [36]>kull
>>Вот как ты можешь доверять Borland...
Даже если бы Borland и не генерировал на самом деле в упомянутом контексте тот самый код, думаю, это вовсе не означало бы наличие явного или неявного бага.
>DiamondShark
Как угодно. На "Вы" - значит, на "Вы". Ваше право, сударь.
А код Ваш (цитирую)
TRec = record
S: DWORD;
end;
и писать
string(Rec.S) := "sljkdflsjdlfjk";
без явной инициализации поля Rec.S дает отказ.
Или будьте предельно точными в высказываниях, подчеркнув предварительно этот факт, коль скоро Вы подчеркиваете свои твердые знания по сабжу.
Так что - будьте так любезны - следите, сударь, за собой, а не за мной - я уж как-нибудь сам справлюсь со своими "отказами".
← →
kull (2002-08-13 18:43) [37]Да никаких Finalize не надо.
Сами, сами строки освобождаются! >:(
← →
DiamondShark (2002-08-13 18:49) [38]
> Digitman © (13.08.02 18:39)
>
> А код Ваш (цитирую)
>
> TRec = record
> S: DWORD;
> end;
>
> и писать
>
> string(Rec.S) := "sljkdflsjdlfjk";
>
> без явной инициализации поля Rec.S дает отказ.
Согласен. Совершенно не рабочий код. При компиляции на строке "и писать" выдается ошибка
[Error] Unit1.pas(123); Illegal character in input file: "и" ($E8)
← →
kull (2002-08-13 18:50) [39]
> Даже если бы Borland и не генерировал на самом деле в упомянутом
> контексте тот самый код, думаю, это вовсе не означало бы
> наличие явного или неявного бага.
Ну если б был баг, то это баг от Borland.
Но сама концепция ( теоретически, не смотря ни на баги, ни на генерируемый код, т.к. это не важно в данном случае) такова, что строки типа string освобождаются сами.
Так в чем же еще загвоздка?
Неужели вы пишете программы, основываясь на возможных багах компилятора?
← →
kull (2002-08-13 18:53) [40]
> DiamondShark © (13.08.02 18:49)
Вах... Да вы шютыник...
Страницы: 1 2 вся ветка
Форум: "Основная";
Текущий архив: 2002.08.22;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.007 c