Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
3-71051
RomaFilatov
2002-08-01 12:11
2002.08.22
Использование TClientDataSet


1-71123
Natali
2002-08-13 08:05
2002.08.22
перевести код с С на Паскаль


1-71140
restless
2002-08-09 15:28
2002.08.22
Повернуть DBNavigator


1-71078
Vitas2
2002-08-11 08:33
2002.08.22
TBitmap


1-71252
Иван
2002-08-12 09:15
2002.08.22
Переменное кол-во параметров





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский