Форум: "Начинающим";
Текущий архив: 2007.07.29;
Скачать: [xml.tar.bz2];
ВнизПроблемы с памятью Найти похожие ветки
← →
Sventitskiy © (2007-07-02 17:38) [0]Добрый день.
У меня следующий вопрос. Имеется динамический массив DArray: array of TIntResultObjected, элементами которого являются записи:
TIntResultObjected=record
WaveLength: real;
Results: TList;
end;
Элементы списка (поле Results) тоже записи вида:
TResultObjectedData=record
X,Y,Z: real;
Value_WaveLength: real;
end;
Программа производит расчет и создает массив. Потом при повторении расчета массив должен уничтожаться а память должна соотв. освобождаться. Я делаю это как:
DArray:=Nil;
Но похоже что этого не достаточно, так как после нескольких расчетов Windows выдает сообщение Out of memory.
Как корректно освободить память?
С уважением,
Александр
← →
авыф (2007-07-02 17:40) [1]SetLength(...,0)?
← →
Desdechado © (2007-07-02 17:42) [2]Пройтись по массиву и Results.Free для каждого элемента.
← →
Loginov Dmitry © (2007-07-02 22:41) [3]> TIntResultObjected=record
> WaveLength: real;
> Results: TList;
> end;
Тут очевидно, уже не запись, а class напрашивается
← →
Sventitskiy © (2007-07-03 00:50) [4]Возможно напрашивается Class но сделано так и нет времени переделывать.
Как все-таки сделать с записью. Проход по массиву и Results.Free для каждого элемента не помогает!!!
← →
Юрий Зотов © (2007-07-03 01:10) [5]Элементы списка TResultObjectedData, по-видимому, тоже создаются в хипе - значит, эту память тоже надо освобождать.
← →
Германн © (2007-07-03 01:14) [6]
> Как все-таки сделать с записью. Проход по массиву и Results.
> Free для каждого элемента не помогает!!!
А какое Free может быть для записи?
← →
icWasya © (2007-07-03 10:24) [7]У вас в коде наверняка есть вот такие строки
SetLength(DArray,Length(DArray)+1);
если вызывать такой код много раз, то будет жуткая фрагментация памяти, что в конце концов приведёт к Out of memory.
Решение - Перераспределять памать в DArray большими блоками,
Не использовать Length(DArray) для указания количества используемых элементов массива, а завести для этого специальную переменную.
например так
var
DArray: array of TIntResultObjected;
LenArray:Integer;
procedure AddToDArray;
begin
Inc(LenArray);
if LenArray>=Length(DArray) then SetLength(DArray,LenArray+100);//или сколько там
DArray[LenArray-1].Results:=TList.Create;
end;
procedure ClearDArray;
var
I:Integer;
begin
for I:= 0 to LenArray-1 do;
DArray[I].Results.Free;
LenArray:=0;
// SetLength(DArray,0);
end;
← →
SlymRO © (2007-07-03 10:35) [8]icWasya © (03.07.07 10:24) [7]
Не проще:TResultObjectedData=record
X,Y,Z:real;
Value_WaveLength:real;
end;
TIntResultObjected=record
WaveLength: real;
Results:array of TResultObjectedData;
end;
само собой убьется...
← →
Desdechado © (2007-07-03 10:55) [9]> А какое Free может быть для записи?
Results: TList;
← →
Anatoly Podgoretsky © (2007-07-03 12:29) [10]Как создавал TResultObjectedData=record
так и уничтожай, естественно в цикле
← →
Sapersky (2007-07-03 14:24) [11]procedure AddToDArray;
Тогда уж так (несколько длинновато, зато универсально):
{$IFDEF DELPHI4or5}
Type
PDynArrayTypeInfo = ^TDynArrayTypeInfo;
TDynArrayTypeInfo = packed record
kind: Byte;
name: string[0];
elSize: Longint;
elType: ^PDynArrayTypeInfo;
varType: Integer;
end;
procedure DynArraySetLength(var a: Pointer; typeInfo: PDynArrayTypeInfo; dimCnt: Longint; lengthVec: PLongint);
asm
push edi
push esi
push ebx
mov esi, lengthVec
mov ebx, ecx
@loop: // first we must push all lengthVec in the stack
mov edi,[esi]
push edi
add esi, 4
dec ebx
jnz @loop
mov ebx, ecx
call system.@DynArraySetLength
imul ebx, $04
add esp, ebx // restoring stack (works like pop)
pop ebx
pop esi
pop edi
end;
{$ENDIF}
// note: if elements are dynarrays, only references are copied
// with ref count increment (DynArrayAsg)
procedure Arr_Copy( Dst, Src : Pointer; Info: PTypeInfo; Cnt: Integer);
asm
push Cnt
CALL System.@CopyArray;
// add esp, 4 // for some reason we don"t need stack restoring
end;
// mostly the same as SetLength, but reallocates array with blocks in TList style
// Length(Arr) plays role of Capacity here,
// so you must keep used array size in separate variable (pass it to NewCount)
procedure Arr_Grow(Var Arr; TypInfo: PDynArrayTypeInfo; NewCount : Integer);
Var Len, Capacity : Integer;
begin
Assert(TypInfo.Kind = Byte(tkDynArray), "Arr_Grow: Only dynamic arrays supported");
If (Pointer(Arr) <> nil) then begin
Len := PInteger(Integer(Arr) - SizeOf(Integer))^;
If (NewCount <= Len) then Exit; // we fit to existing capacity, no need to grow
Capacity := Len * 2; // not sure this will be always best way...
If Capacity < NewCount then Capacity := NewCount;
end else
Capacity := NewCount; // was no array - just allocate NewCount elements
DynArraySetLength(Pointer(Arr), TypInfo, 1, @Capacity);
end;
function Arr_AddItem(Var Arr; TypInfo: PDynArrayTypeInfo; Var Count : Integer;
Src: PByte = nil; AtPos : Integer = -1): Pointer;
Var Dst : PByte;
ElSize : Integer;
begin
Arr_Grow(Arr, TypInfo, Count + 1);
Inc(PByte(TypInfo), Length(TypInfo.Name)); ElSize := TypInfo.elSize;
Dst := PByte(Arr);
If (AtPos >= 0) and (AtPos < Count) then begin
Inc(Dst, AtPos * ElSize);
Move(Dst^, PByte( Integer(Dst) + ElSize )^, ElSize * (Count - AtPos));
If (TypInfo.elType <> nil) then FillChar(Dst^, ElSize, 0);
end else
Inc(Dst, Count * ElSize);
Result := Dst;
If (Src <> nil) then
If TypInfo.elType <> nil then Arr_Copy(Dst, Src, PTypeInfo(TypInfo.elType^), 1)
else Move(Src^, Dst^, TypInfo.elSize);
Inc(Count);
end;
TypInfo добывается как TypeInfo(<тип массива>).
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2007.07.29;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.066 c