Есть ли тут утечка памяти?

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Есть ли тут утечка памяти?

Сообщение GrayEddy » 12.07.2010 11:34:18

Перелопачиваю проект, доставшийся по наследству. В нем постепенно растет память, особенно виртуальная.
Решил посмотреть, где явно выделяется память. И вот наткнулся на такой кусок кода
Код: Выделить всё
procedure TMainForm.RemoveCommand(commIndex_: byte);
var i,j:integer;
begin
  for i:=0 to CommandCount-1 do
    if Commands[i].CommIndex=commIndex_ then break;
   if i<CommandCount then
     begin
       Сommands[i].Destroy;   // <---  1
       for j:=i to CommandCount-2 do
         Commands[j]:=commands[j+1]; // <---  2
       dec(CommandCount); 
       setlength(Commands,CommandCount);
    end;
end;

Здесь пояснения. Commands - динамический одномерныйц массив класса TCommand (который унаследован от TObject) длиной High(Byte).
В пункте 1 безусловно, надо заменить на Сommands[i].Free;
Алгоритм очень прост. По значению commIndex_ находим нужный нужный нам элемент массива и осовобождаем его.
Затем сдвигаем элементы массива справа налево правее освобожденного.
В результате этого в пункте 2 последний и предпоследний элементы указывают на один и тот же экземпляр класса. Вот этот момент и смущает.
Затем массив обрезается на 1 элемент, последний элемент уходит из зоны видимости.
GrayEddy
постоялец
 
Сообщения: 375
Зарегистрирован: 06.05.2005 09:37:56

Re: Есть ли тут утечка памяти?

Сообщение Light13 » 12.07.2010 11:53:50

Насчет FPC не скажу точно, но в delphi компилятор не гарантирует сохранность значения переменной цикла с параметром после выхода из цикла.
After the for statement terminates (provided this was not forced by a break or an exit procedure), the value of counter is undefined.
Аватара пользователя
Light13
постоялец
 
Сообщения: 127
Зарегистрирован: 17.07.2009 07:50:10
Откуда: Челябинск

Re: Есть ли тут утечка памяти?

Сообщение GrayEddy » 12.07.2010 11:56:33

Да, это Delphi проект.
GrayEddy
постоялец
 
Сообщения: 375
Зарегистрирован: 06.05.2005 09:37:56

Re: Есть ли тут утечка памяти?

Сообщение Light13 » 12.07.2010 12:01:50

Уменьшение длины массива не играет роли, там ведь только указатели на объекты хранятся
Попробуйте так сделать:
Код: Выделить всё
procedure TMainForm.RemoveCommand(commIndex_: byte);
  var
    i,j: Integer;
begin
  for i:=0 to CommandCount - 1 do
    if Commands[i].CommIndex = commIndex_ then
      begin
           Commands[i].Free;

           for j:=i to CommandCount - 2 do
             Commands[j]:=commands[j + 1];

           CommandCount:=CommandCount - 1;

           setlength(Commands, CommandCount);

           Break;
      end;
end;


Добавлено спустя 5 минут 17 секунд:
В своих проектах взял привычку добавлять модуль с кодом
Код: Выделить всё
interface

implementation

uses
  Windows;

initialization

finalization
  if AllocMemCount <> 0 then
    MessageBox(0, 'Ошибка освобождения памяти.' ,'Память не освобождена полностью.', MB_OK or MB_ICONERROR or MB_TASKMODAL);


затем прописываем этот модуль первым в файле проекта, поймали сообщение - смотрим код ;)
Аватара пользователя
Light13
постоялец
 
Сообщения: 127
Зарегистрирован: 17.07.2009 07:50:10
Откуда: Челябинск

Re: Есть ли тут утечка памяти?

Сообщение Bupyc » 12.07.2010 12:08:34

Честно говоря, утечек памяти я здесь на первый взгляд не вижу, но есть пара моментов, которые мозолят глаза.

1. Не нравится мне использование цикловой переменной i после цикла. Компилятор никаких ворнингов случаем не выдает?
2. Если CommandCount = 0, то на строке setlength(Commands,CommandCount) FreePascal может вывалиться с Exception. Я обычно такое отслеживаю и если CommandCount = 0, то Commands := nil;

P.S. Вообще я бы этот кусок кода переписал. Времени уйдёт минут 10, и не нужно будет разбираться как он работает.
Bupyc
постоялец
 
Сообщения: 137
Зарегистрирован: 29.08.2007 18:22:42

Re: Есть ли тут утечка памяти?

Сообщение GrayEddy » 12.07.2010 12:37:56

1. Нет, варнингов нет. Мы не меняем значение i в самом цикле.
2. Спасибо, учту.

Думаю просто создать новый проект, там 2500 строк кода.
GrayEddy
постоялец
 
Сообщения: 375
Зарегистрирован: 06.05.2005 09:37:56

Re: Есть ли тут утечка памяти?

Сообщение Дож » 12.07.2010 16:10:28

Если CommandCount = 0, то на строке setlength(Commands,CommandCount) FreePascal может вывалиться с Exception. Я обычно такое отслеживаю и если CommandCount = 0, то Commands := nil;

Это как такое можно получить?

Меня это беспокоит, потому что уже второй год использую массивы, и очень часто делаю SetLength(..., 0), но исключений не словил. Использую Win32 компилятор.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Есть ли тут утечка памяти?

Сообщение Bupyc » 12.07.2010 19:23:40

У меня было такое под линуксом, при компиляции через командную строку. Выскакивал exception что то типа Range Check Error. Возможно, лечится указанием соответствующей директивы компилятора. Я не разобрался, просто поправил нужный кусок кода.
Bupyc
постоялец
 
Сообщения: 137
Зарегистрирован: 29.08.2007 18:22:42

Re: Есть ли тут утечка памяти?

Сообщение Дож » 12.07.2010 20:03:17

«Range Check Error» скорее всего возник из-за попытки обратиться к какому-то элементу массива, после того как размер массива установлен в 0.
Commands[High(Commands)] вполне может к этому привести.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Есть ли тут утечка памяти?

Сообщение Bupyc » 13.07.2010 14:51:03

Нет, таких попыток не было. Exception был именно на строке SetLength.
Bupyc
постоялец
 
Сообщения: 137
Зарегистрирован: 29.08.2007 18:22:42


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 22

Рейтинг@Mail.ru