При использовании динамически распределяемых переменных часто возникает общая проблема, называемая утечкой динамической памяти. Утечка памяти - это ситуация, когда пространство выделяется в динамически распределяемой памяти и затем теряется - по каким-то причинам ваш указатель не указывает больше на распределенную область, так что вы не можете освободить пространство.
Общей причиной утечек памяти является переприсваивание динамических переменных без освобождения предыдущих. Простейшим случаем является следующий:
var IntPointer: ^Integer;
begin
New(IntPointer);
New(IntPointer);
end.
При первом вызове New в динамически распределяемой памяти выделяется 8 байт, и на них устанавливается указатель IntPointer. Второй вызов New выделяет другие 8 байт, и IntPointer устанавли- вается на них. Теперь у вас нет указателя, ссылающегося на первые 8 байт, поэтому вы не можете их освободить. В программе эти байты будут потеряны.
Утечка памяти происходит и тогда, когда требуется изменить значение указателя, например, заставить его указывать на другую переменную.
Поясним сказанное на примере.
var a,b:^integer;
begin
new(a); new(b);
a^:=10; b^:=5;
a:=b;
b:=nil;
end.
В данном примере после выполнения оператора a:=b на динамический объект co значением 10 не указывает ни одна ссылка, т.е. он становится недоступным для программы. С другой стороны, в результате выполнения этого же оператора не образуется новый динамический объект со значением 5, а указатель a ссылается на тот же существующий объект, на который ссылается и указатель b.
В динамической памяти остаются «потерянные» данные (мусор), которые недоступны для программы. Поэтому память не может быть освобождена. Происходит утечка памяти.
Естественно, утечка памяти может быть не такой очевидной, как в наших примерах. Выделение памяти почти никогда не происходит в последовательных операторах, но может выполняться в отдельных процедурах или далеко отстоящих друг от друга частях программы.
Чтобы избежать подобной ситуации необходимо перед переприсваиванием указателя с помощью процедуры dispose освобождать область памяти, на которую он ссылается, а указателю присваивать значение nil. Тогда при попытке распределить их снова вы можете убедиться что они имеют значение nil:
var a,b:^integer;
begin
new(a); new(b);
a^:=10; b^:=5;
dispose(a); a:=nil;
if a=nil then a:=b;
b:=nil;
end.
|