![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
утечка памяти [D7, WinXP]
Цукор 5 © (2005-09-12 19:42:00)В продолжении ветки http://www.delphimaster.ru/cgi-bin/forum.pl?id=1126429711&n=0.Итак,имеется код(для простоты я всё сделал без DLL) :
type
TMyRetVal=record
Line1:ShortString;
Line2:ShortString;
Dept : Byte;
end;
type
PMyRetVal = ^TMyRetVal;
function GetVal(Inp1,Inp2:Integer;Q:PMyRetVal):Boolean;
var I:Integer;
begin
Randomize;
for I:=Inp1 to Inp2 do
begin
Q^.Line1:='Line1_'+IntToStr(I);
Q^.Line2:='Line2_'+IntToStr(I);
Q^.Dept :=random(9);
Inc(Q);
end;
Result:=True;
end;
procedure TForm1.Button1Click(Sender: TObject);
var Q:PMyRetVal;
I:Integer;
Inp1,Inp2:Integer;
begin
Inp1:=1;
Inp2:=842;
GetMem(Q,(Inp2-Inp1+1)*SizeOf(TMyRetVal));
GetVal(Inp1,Inp2,Q);
for i:=0 to (Inp2-Inp1) do
begin
Memo1.Lines.Add(Q^.Line1);
Memo1.Lines.Add(Q^.Line2);
Memo1.Lines.Add(IntToHex(Q^.Dept,2));
Inc(Q);
end;
Q:=nil;// без нее AV! Хотя,я думаю в этом и беда :(
FreeMem(Q);
end;
Получаю утечку памяти на все длинну структуры :( Какие будут предложения?
Ihor Osov'yak (2005-09-12 22:01:00) [1]2 [10] Неважно (12.09.05 21:43)
Один из вариантов:
type
TMyRetVal = record
Line1: ShortString;
Line2: ShortString;
Dept: Byte;
end;
PMyRetValArray = ^TMyRetValArray;
TMyRetValArray = array[0..$FFFFF] of TMyRetVal;
function GetVal(aLen: integer; aArr: PMyRetValArray): Boolean;
var
idx: Integer;
begin
//Randomize; - рандомайз желательно использовать только один раз, например в секции инициализации
for idx := 0 to aLen - 1 do
with aArr[idx] do
begin
Line1 := 'Line1_' + IntToStr(idx);
Line2 := 'Line2_' + IntToStr(idx);
Dept := random(9);
end;
Result := True;
end;
некоторые дополнительные расходы, связанные с типизацией (только время на написание нескольких строчек) с лихвой окупаются более прозрачным кодом.
Цукор 5 (2005-09-12 21:55:00) [2]2 Ihor Osov'yak © (12.09.05 20:46) [8]
>а случайно вычисление типа 2+2 посредством написания цикла осуществлять не приходилось?
Уже и пошутить нельзя...
Dec(Q,Inp2-Inp1+1);
Неважно (2005-09-12 21:43:00) [3]2 Ihor Osov'yak ©
> Все же иззбегайте такого стиля написания кода.
Покажите как надо. Буду очень благодарен ;)
Ihor Osov'yak (2005-09-12 20:49:00) [4]относительно [7] Ihor Osov'yak © (12.09.05 20:45)
в function GetVal... не заметил inc(Q) - прошу извинить. Замечание относительно инициализации только первого элемента буфера снимается :-).
Но. Все же иззбегайте такого стиля написания кода.
Ihor Osov'yak (2005-09-12 20:46:00) [5]2 [6] Цукор 5 (12.09.05 20:43)
а случайно вычисление типа 2+2 посредством написания цикла осуществлять не приходилось?
Ihor Osov'yak (2005-09-12 20:45:00) [6]2 Цукор 5
Подсказка намбер ван:
Подумайте, что делает function GetVal... Наводящая подсказка - изменится эффект от работы этой функции, если вместо Inp2:=842;
написать Inp2:=248; (я не имею ввиду количестов выполнений тела цикла внутри функции).
Теперь по существу.
в procedure TForm1.Button1Click на втором прохождении цикла (после того, как будет выполнено Inc(Q);) по Q^.Line1 и Q^.Line2 будет идти обращение к областям памяти, где вместо короткой строки будет находится мусор. Код будет пытаться преобразовать этот мусор к AnsiString, и первый этап будет состоять в поиске терминального зеро-символа (так как предполагается все же наличие строки, а не мусора). Не факт, что этот символ будет присутствовать. И как следствие в процессе поиска будет сделана попытка чтения по адресу за пределами распределенной памяти. Следствие этого следствия - исключение.
Но это вероятностный сценарий. Если эттого не произодет, то случится неминуемо следующее:
Q:=nil;// без нее AV! Хотя,я думаю в этом и беда :
FreeMem(Q); - понятно, что здесь ничего не освобождается, так как Q уже nil. Как следствие - утечка.
Если же убрать Q:=nil - то нужно вспомнить, что Q вследствие наличия Inc(Q); в теле цікла уже будет за пределами распределенной памяти. А это гарантированное исключение.
Цукор 5 (2005-09-12 20:43:00) [7]2 AlexWlad © (12.09.05 20:37) [5]
Спасибо,догнал ;) Сделал так :
for i:=0 to (Inp2-Inp1) do Dec(Q);
AlexWlad (2005-09-12 20:37:00) [8]Цукор 5 (12.09.05 20:16) [4]
Invalid Pointer Operation у тебя из-за "...в цикле делаешь Inc(Q);, тем самым изменяя адрес начала выделенного блока памяти...". Тебе надо завести 2 переменных типа PMyRetVal, второй переменной присвоить значение первой после гетмем и использовать ее в цикле. Таким образом, ты не теряешь адрес блока памяти. И в конце - FreeMem (nil - по вкусу). Цикл имеется в виду в обработчике кнопки.
Цукор 5 (2005-09-12 20:16:00) [9]2 AlexWlad © (12.09.05 19:50) [2]
>Во-первых - сначала FreeMem, и только потом МОЖНО (но не обязательно) :=nil.
Не получается. Я же написал в комментариях. Если без Q:=nil; а сразу FreeMem(Q); то Invalid Pointer Operation.
2 Anatoly Podgoretsky © (12.09.05 19:56) [3]
Мне непонятны Ваши слова. Предложения по сабжу будут???
Anatoly Podgoretsky (2005-09-12 19:56:00) [10]Это означает, что и утечка и AV закономерны.
AlexWlad (2005-09-12 19:50:00) [11]
Q:=nil;// без нее AV! Хотя,я думаю в этом и беда :(
FreeMem(Q);
Во-первых - сначала FreeMem, и только потом МОЖНО (но не обязательно) :=nil.
А самое главное - ты в цикле делаешьInc(Q);, тем самым изменяя адрес начала выделенного блока памяти. Так что все в норме.
Цукор 5 (2005-09-12 19:44:00) [12]Опс...структура вот такая :
type
TMyRetVal=record
Line1:String[25];
Line2:String[25];
Dept : Byte;
end;
Она меньше весит,все же.