![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема с освобождением памяти [D5, Win2k]
Duncan © (2004-06-16 15:23:00)Я создаю список, через некоторое время кидаю его в БД и освобождаю. Но в результате оперативка тает на глазах и не освобождается. Освобождается она только после завершения программы, но т.к. мне нужен сервис, то соответственно постоянно оперативка пожирается при попытке обработать очередной файл. Вот структура и процедура уничтожения списка:
//По горизонтали идет идут данные PTIP_B, для каждого из которого в низ идут данные типа PTIP_A.
type Traf=record
IP_A, IP_B:longword;
ASN_A, ASN_B, INT_A, INT_B:word;
BYTES_A, BYTES_B: longword;
DT: TDateTime;
end;
PTIP_A=^TIP_A;
TIP_A=record
down:PTIP_A;
IP_A:longword;
INT_A, int_B, ASN_A, ASN_B:word;
BYTES_A, BYTES_B: longword;
DT: TDateTime;
end;
PTIP_B=^TIP_B;
TIP_B=record
next:PTIP_B;
down:PTIP_A;
IP_B:longword;
end;
procedure SaveAndDestroy;
var
i, count:integer;
p,p1:PTIP_B;
a,a1:PTIP_A;
begin
new(p);
wtr.StartTransaction;
for i:=0 to 255 do begin
p:=arrpoint[i];
while (p<>nil) do begin
new(a); a:=p^.down;
while (a<>nil) do begin
with qIns do begin
//Пишем в бд
end;
inc(count);
if count>700 then begin
wtr.Commit; count:=count-700;
wtr.StartTransaction; end;
new(a1); a1:=a;
a:=a^.down; dispose(a1);
end;
dispose(a); new(p1);
p1:=p; p:=p^.next; dispose(p1); end;
arrpoint[i]:=nil; end;
wtr.Commit;
dispose(p);
end;
cyborg (2004-06-17 17:42:00) [1]Чтобы присвоить значения, которые хранятся по указателям нужно не p:=zделать, а использовать Move(P^,Z^,SizeOf(Z));
Duncan (2004-06-17 16:06:00) [2]Спасибо всем кто пытался помочь.
Duncan (2004-06-17 16:00:00) [3]Sandman25 © (17.06.04 15:46) [38]
Может и заставит :) Но такие механические действия не должны влиять на логику работы с памятью :( Вообщем буду еще как-то пытаться ковырять эту лабуду.
Sandman25 (2004-06-17 15:46:00) [4][37] Duncan (17.06.04 15:24)
а вот дальше уже самостоятельно. Может эта мука с отладкой заставит Вас использовать процедуры вместо копирования кусков кода.
Duncan (2004-06-17 15:24:00) [5]Ну да лоханулся, поменял на следующий вид, но ничего не изменилось
procedure AddIP_A(var d1:PTIP_A);
var q_a,d,q:PTIP_A;
l:integer;
begin
l:=0; new(q_a);
if (d1=nil) or (d1^.IP_A>tr.IP_A) then begin
q_a^.down:=d1; d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT end
else begin
q:=d1; d:=q;
while (q<>nil) do begin
l:=l+1;
if q^.IP_A<tr.IP_A then begin d:=q; q:=Q^.down; end
else if q^.IP_A>tr.IP_A then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break end
else if q^.INT_A<tr.INT_A then begin d:=q; q:=Q^.down; end
else if q^.INT_A>tr.INT_A then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break end
else if q^.INT_B<tr.INT_B then begin d:=q; q:=Q^.down; end
else if q^.INT_B>tr.INT_B then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break end
else if q^.ASN_A<tr.ASN_A then begin d:=q; q:=Q^.down; end
else if q^.ASN_A>tr.ASN_A then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break; end
else if q^.ASN_B<tr.ASN_B then begin d:=q; q:=Q^.down; end
else if q^.ASN_B>tr.ASN_B then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break end
else begin
q^.BYTES_A:=q^.BYTES_A+tr.BYTES_A;
q^.BYTES_B:=q^.BYTES_B+tr.BYTES_B;
dispose(q_a);
break end; end;
if (q=nil) then begin
q_a^.down:=q; d^.down:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT end
end
end;
Sandman25 (2004-06-17 15:01:00) [6]То есть new(d)
Sandman25 (2004-06-17 14:59:00) [7]Ну вот, Вам же говорили про ошибку в другом месте :)
new(q_a); new(d); new(q);
d:=q; l:=0;
и как Вы после этого собираетесь освобождать память, занятую при new(q)?
Duncan (2004-06-17 14:57:00) [8]Аналогично только добавляется ветка вниз:
procedure AddIP_A(var d1:PTIP_A);
var q_a,d,q:PTIP_A;
l:integer;
begin
new(q_a); new(d); new(q);
d:=q; l:=0;
if (d1=nil) or (d1^.IP_A>tr.IP_A) then begin //Если список пуст или надо добавить в начале
q_a^.down:=d1; d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT end
else begin
q:=d1;
while (q<>nil) do begin //Пока не конец
l:=l+1; //Отслеживаем уровень
if q^.IP_A<tr.IP_A then begin d:=q; q:=Q^.down; end //Спускаемся вниз
else if q^.IP_A>tr.IP_A then begin //иначе добавляем
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break
end //Дальше аналогично только для других параметров
else if q^.INT_A<tr.INT_A then begin d:=q; q:=Q^.down; end
else if q^.INT_A>tr.INT_A then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break end
else if q^.INT_B<tr.INT_B then begin d:=q; q:=Q^.down; end
else if q^.INT_B>tr.INT_B then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break end
else if q^.ASN_A<tr.ASN_A then begin d:=q; q:=Q^.down; end
else if q^.ASN_A>tr.ASN_A then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break; end
else if q^.ASN_B<tr.ASN_B then begin d:=q; q:=Q^.down; end
else if q^.ASN_B>tr.ASN_B then begin
q_a^.down:=q;
if l>1 then d^.down:=q_a else d1:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT;
break end
else begin
q^.BYTES_A:=q^.BYTES_A+tr.BYTES_A;
q^.BYTES_B:=q^.BYTES_B+tr.BYTES_B;
break end; end;
if (q=nil) then begin //Если мы дошли до конца списка
q_a^.down:=q; d^.down:=q_a;
q_a^.IP_A:=tr.IP_A; q_a^.INT_A:=tr.INT_A;
q_a^.int_B:=tr.INT_B; q_a^.ASN_A:=tr.ASN_A; q_a^.ASN_B:=tr.ASN_B;
q_a^.BYTES_A:=tr.BYTES_A; q_a^.BYTES_B:=tr.BYTES_B; q_a^.DT:=tr.DT end
end
end;
Sandman25 (2004-06-17 14:49:00) [9][32] Duncan (17.06.04 14:39)
Это тоже вроде правильно, за исключением многократного дублирования, усложняющего понимание и поиск ошибок. А в AddIP_A что делается?
Duncan (2004-06-17 14:39:00) [10]Ну вот так у меня все это дело формируется:
p^.next:=arrpoint[tr.ip_b div 16777216];
if (p^.next<>nil) and (p^.next^.IP_B<=tr.IP_B) then begin //Если список не пуст
p:=p^.next; q:=p;
if p^.IP_B=tr.IP_B then AddIP_A(p^.down) //Добавляем ветку вниз
else begin
p:=p^.next;
while (p<>nil) do //Идем горизонтально по списку
if p^.IP_B=tr.IP_B then begin
AddIP_A(p^.down); break; //Нашелся одинаковый элемент, добавляем ветку вниз
end
else if p^.IP_B<tr.IP_B then begin
q:=p; p:=p^.next; //Пока значение меньше переходим дальше по списку
end
else begin //иначе вставляем элемент между предыдущим (q) и текущим элементом (p)
new(q_b); q_b^.next:=p;
q^.next:=q_b; q_b^.IP_B:=tr.IP_B;
q_b^.down:=nil; AddIP_A(q_b^.down);
break end;
if (p=nil) then begin //Если конец списка
new(q_b); q_b^.next:=p;
q^.next:=q_b; q_b^.IP_B:=tr.IP_B;
q_b^.down:=nil; AddIP_A(q_b^.down); end;
end end
else begin //Либо пустой список, либо после головы списка вставлять надо
new(q_b); q_b^.next:=p^.next; q_b^.IP_B:=tr.IP_B;
arrpoint[tr.ip_b div 16777216]:=q_b;
q_b^.down:=nil; AddIP_A(q_b^.down); end;
p:=nil;
Тимохов (2004-06-17 14:28:00) [11]
> Вообщем если есть возможность и желание давай пообщаемся
> в аське 24753812.
аська у меня закрыта.
Вообще-то это не совсем список. Не знаю как по науке это назвается, я бы назвал двумерный список.
Я вряд ли тебе помогу - надо копать остальные исходники, а на это времени нет :(
Еще раз говорю - проверьте логику заполнения списка. Она должно соответствовать логике освобожденя списка. С учетом того, что в первоначальном вашем методе была масса ошибок - думаю при заполнении списка их не меньше.
Duncan (2004-06-17 14:21:00) [12]В том то все и дело, что в массиве arrpoint храняться так называемые головы (head) списков. Их всего 256 штук. Соответственно каждый из них указывает на элемент типа PTIP_B.
Единственное что массив описан так: ArrPoint: array [0..255] of Pointer;
При этом если бы они только не освобождались то потерялось бы не так много памяти.
Вообщем если есть возможность и желание давай пообщаемся в аське 24753812.
Тимохов (2004-06-17 14:13:00) [13]
> Причем я уверен, что проблема именно в этом месте.
зря уверены. в самом коде ничего криминального нет.
я тоже уверен.
смотрите внимательнее как вы создаете arrpoint. проверьте глазами соответствует ли логика освобождения массива логике заполнения массива?
Duncan (2004-06-17 14:01:00) [14]Тимохов © (17.06.04 13:52) [27]
Я ужастно дико извиняюсь, понимаю что всех уже достал тут, но очень надо. Причем я уверен, что проблема именно в этом месте. Могу прислать исходники если они помогут, хотя они написаны опять таки в стиле удобном мне для чтения.
Тимохов (2004-06-17 13:52:00) [15]
> Duncan (17.06.04 13:40) [25]
судя по всему ошибка в другом месте
Тимохов (2004-06-17 13:51:00) [16]
> С уважением, Анатолий!
сомневаюсь
Duncan (2004-06-17 13:40:00) [17]Digitman © (16.06.04 17:33) [24]
Спасибо, мне это итак уже здесь разжували ...
Но вот только никто толком не смог мне сказать как память списка очистить. А если Вы считаете что я тупой, то будьте любезны потратьте 5-7 минут и модифицируйте мой неправильный код в более верный.
procedure SaveAndDestroy;
var
i:integer;
p,p1:PTIP_B;
a,a1:PTIP_A;
begin
for i:=0 to 255 do begin
p:=arrpoint[i];
while (p<>nil) do begin
a:=p^.down;
while (a<>nil) do begin
a1:=a^.down;
dispose(a);
a:=a1;
end;
p1:=p^.next;
dispose(p);
p:=p1;
end;
arrpoint[i]:=nil; end;
end;
С уважением, Анатолий!
P.S. Заранее огромное спасибо!
Digitman (2004-06-16 17:33:00) [18]
> Duncan (16.06.04 15:36) [5]
Просто я это в универе проходил
> .., но мы там вроде именно так и писали
если ты в "универе" не постиг банальной истины а-ля
New(P);
//до момента Dispose() не трожь кривыми руками указательную переменную Р ! И неважно, цикл или не цикл !
....
Dispose(Р);
Sandman25 (2004-06-16 17:18:00) [19][22] Duncan (16.06.04 17:11)
Вроде все правильно, насколько я понимаю. Может, где-то еще память выделяется.
Duncan (2004-06-16 17:11:00) [20]Написал процедуру следующим образом, но ничего не помогает, память по прежнему расходуется.
procedure SaveAndDestroy;
var
i, count:integer;
p,p1:PTIP_B;
a,a1:PTIP_A;
begin
wtr.StartTransaction;
for i:=0 to 255 do begin
p:=arrpoint[i];
while (p<>nil) do begin
a:=p^.down;
while (a<>nil) do begin
with qIns do begin
ParamByName('IP_A').AsInt64:=a^.IP_A; ParamByName('IP_B').AsInt64:=p^.IP_B;
ParamByName('ASN_A').AsInteger:=a^.ASN_A; ParamByName('ASN_B').AsInteger:=a^.ASN_B;
ParamByName('INT_A').AsInteger:=a^.INT_A; ParamByName('INT_B').AsInteger:=a^.INT_B;
ParamByName('BYTES_A').AsInt64:=a^.BYTES_A; ParamByName('BYTES_B').AsInt64:=a^.BYTES_B;
ParamByName('DT').AsDateTime:=a^.DT; ExecQuery end;
inc(count);
if count>700 then begin
wtr.Commit; count:=count-700;
wtr.StartTransaction; end;
a1:=a^.down; dispose(a);
a:=a1; end;
p1:=p^.next; dispose(p);
p:=p1; end;
arrpoint[i]:=nil; end;
wtr.Commit;
end;