Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> освобождение памяти при удалении узлов в дереве 
V
    Опции темы
uwannadie
Дата 4.4.2010, 11:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



заполняю VirtualStringTree данными, имеющими следующую структуру
Код

type
  TFilePriority =
      (fpNormal,    //обычный файл
       fpCritical,  //файл, критический для корректной работы программы
       fpAbsolute); //файл, который будет обновляться в любом случае

type
  PFileInfo = ^TFileInfo;

  TFileInfo = record
    FileName: String; //полный путь к файлу
    TreeName: String; //название узла в дереве
    FilePriority: TFilePriority;
    ImageIndex: Byte;
  end;

Заполняется дерево следующим образом
Код

procedure TfrmCreateNewUpdate.FillTreeviewWithFiles(directory: string; pTree: TVirtualStringTree; pNode: PVirtualNode);
var
  Mysearch: TSearchRec;
  FldrNode: PVirtualNode;
  FileData: PFileInfo;
begin
  if directory[Length(directory)] <> '\' then
    directory := directory + '\';
  pTree.BeginUpdate;
  if FindFirst(directory + '*.*', faDirectory, Mysearch) = 0 then
  begin
    repeat
      //поиск папок
      if ((Mysearch.Attr and faDirectory) = faDirectory) and (Mysearch.Name[1] <> '.') then
      begin
        if (Mysearch.Attr and faDirectory > 0) then
        begin
          pNode := pTree.AddChild(pNode,nil);
          FileData := pTree.GetNodeData(pNode);
          if Assigned(FileData) then
          with FileData^ do
          begin
            FileName := Directory + Mysearch.Name;
            TreeName := Mysearch.Name;
            FilePriority := fpNormal;
            ImageIndex := 0;
          end;
        end;
        FldrNode := pNode.Parent;
        FillTreeviewWithFiles(directory + Mysearch.Name + '\', pTree, pNode);
        pNode := FldrNode;
      end;
    until FindNext(Mysearch) <> 0;
      FldrNode := pNode;
  if FindFirst(directory + '*.*', $23, Mysearch) = 0 then
  begin
    repeat
      //поиск файлов
      pNode := pTree.AddChild(FldrNode,nil);
      FileData := pTree.GetNodeData(pNode);
      if Assigned(FileData) then
      with FileData^ do
      begin
        FileName := Directory + Mysearch.Name;
        TreeName := Mysearch.Name;
        FilePriority := fpNormal;
        ImageIndex := 1;
      end;
    until FindNext(Mysearch) <> 0;
  end;
  FindClose(Mysearch);
  end;
  pTree.EndUpdate;
end;

в событии OnFreeNode написано следующее:
Код

procedure TfrmCreateNewUpdate.vtProjectFilesFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  FileData: PFileInfo;
begin
  FileData := Sender.GetNodeData(Node);
  if Assigned(FileData) then
    Finalize(FileData^);
end;

вопрос: почему при удалении всех узлов дерева, последующем выполнение
Код

vtProjectFiles.Clear;

и заполнении дерева аналогичными данными объем занимаемой памяти увеличивается. при этом FastMM ругается на утечки памяти:
Код

--------------------------------2010/4/3 22:38:40--------------------------------
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):

21 - 36 bytes: UnicodeString x 1617
37 - 52 bytes: UnicodeString x 1962
53 - 68 bytes: UnicodeString x 459
69 - 84 bytes: TStringList x 1, UnicodeString x 84
85 - 100 bytes: UnicodeString x 90
101 - 116 bytes: UnicodeString x 33
117 - 132 bytes: UnicodeString x 21
133 - 148 bytes: UnicodeString x 42
149 - 164 bytes: UnicodeString x 54
165 - 180 bytes: UnicodeString x 54
181 - 212 bytes: UnicodeString x 1974
213 - 244 bytes: UnicodeString x 1290
245 - 276 bytes: UnicodeString x 516
277 - 308 bytes: UnicodeString x 99
309 - 340 bytes: UnicodeString x 12
341 - 388 bytes: UnicodeString x 3


--------------------
PM MAIL   Вверх
Dom
Дата 4.4.2010, 16:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Хм, наугад - утечки UnicodeString, а поля в записи типа String. Какая версия Делфи? Может это утечки и не в дереве?

Ну и можно попробовать освобождать память, вручную затирая строки:
Код

procedure TfrmCreateNewUpdate.vtProjectFilesFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  FileData: PFileInfo;
begin
  FileData := Sender.GetNodeData(Node);
  if Assigned(FileData) then
    with FileData^ do
    begin
      FileName := '';
      TreeName := '';
    end;
end;

PM MAIL   Вверх
uwannadie
Дата 4.4.2010, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



пробовал, перед тем, как создавать тему. не помогает
RAD Studio 2010 Architect

Это сообщение отредактировал(а) uwannadie - 4.4.2010, 16:27
--------------------
PM MAIL   Вверх
kami
Дата 4.4.2010, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Из лога FastMM приведен только конец. Самое интересное - в нем фигурирует TstringList, а в приведенном коде его не наблюдается. Смотри по полному логу, где он (TStringList) создается и уничтожается.
PM MAIL WWW   Вверх
uwannadie
Дата 4.4.2010, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



при всем этом программа обрабатывает данные без сучка и задоринки, но если раз 10-12 очистить и заполнить дерево аналогичными данными, то размер программы в оперативке легко возрастает до 50-60 мб
--------------------
PM MAIL   Вверх
Dom
Дата 4.4.2010, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Так может все-таки дело действительно не в записях дерева, если ручное затирание не помогает?
Может попробовать не очищать узлы в дереве и посмотреть добавятся в этом случае новые утечки или нет? По идее должны, хотя как работают новые версии Делфи я не знаю, знаком только с Д7. Если добавятся, то это уже точно будут из дерева, и следовательно нынешние вызваны чем-то другим.
PM MAIL   Вверх
uwannadie
Дата 4.4.2010, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



Цитата(kami @ 4.4.2010,  16:33)
Из лога FastMM приведен только конец. Самое интересное - в нем фигурирует TstringList, а в приведенном коде его не наблюдается. Смотри по полному логу, где он (TStringList) создается и уничтожается.

стринглист освобождается в другом месте. в нем находится список http ссылок (а-ля зеркал обновления). 
--------------------
PM MAIL   Вверх
kami
Дата 4.4.2010, 16:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Цитата(uwannadie @  4.4.2010,  16:35 Найти цитируемый пост)
стринглист освобождается в другом месте. 

Значит не освобождается. Или освобождается, но не тот. Смотри ПОЛНЫЙ лог, найди в нем поиском сообщение о создании и не-высвобождении TStringList (будет дано всё, вплоть до конкретной строчки модуля). Оттуда и плясать.
PM MAIL WWW   Вверх
uwannadie
Дата 4.4.2010, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



вот создание данного списка
Код

procedure TfrmCreateNewUpdate.sbtnSettingsSelectClick(Sender: TObject);
begin
  if not SelectDirectory('Укажите путь к клиентской части системы обновления','', SettingsPath) then Exit
  else
    lbeUpdClientpath.Text := SettingsPath;
  if not FileExists(SettingsPath + '\settings.ini') then
  begin
    UpdateMirrors := TStringList.Create;
    UpdateRev := 1;
    seUpdRev.MinValue := UpdateRev;
    lbeRelativePathToExe.Text := '';
    btnUpdMirrors.Enabled := True;
    btnSaveINI.Enabled := True;
    seUpdRev.Enabled := True;
  end;
end;

вот освобождение памяти
Код

procedure TfrmCreateNewUpdate.btnSaveINIClick(Sender: TObject);
var
  MyINI: TIniFile;
  i: integer;
begin
  DeleteFile(SettingsPath + '\settings.ini');
  MyINI := TIniFile.Create(SettingsPath + '\settings.ini');
  MyINI.WriteString('Client Settings','RelativePath', lbeRelativePathToExe.Text);
  MyINI.WriteInteger('Client Settings','UpdateRevision', UpdateRev);
  MyINI.WriteInteger('Update Mirrors','Count', UpdateMirrors.Count);
  for I := 0 to  UpdateMirrors.Count - 1 do
    MyINI.WriteString('Update Mirrors','Mirror#' + IntToStr(i + 1),UpdateMirrors.Strings[i]);
  MyINI.Free;
  UpdateMirrors.Free;
end;



--------------------
PM MAIL   Вверх
kami
Дата 4.4.2010, 16:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Цитата(uwannadie @  4.4.2010,  16:40 Найти цитируемый пост)
вот освобождение памяти

FastMM говорит именно об этом списке?
PM MAIL WWW   Вверх
uwannadie
Дата 4.4.2010, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



у меня в программе он единственный (по-крайней мере я больше не создавал)
--------------------
PM MAIL   Вверх
Dom
Дата 4.4.2010, 16:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



В целом немного необычно, когда глобальнае переменная создается по одной кнопке и уничтожается по другой. Обычно я например ставлю это в процедуры создания/удаления формы. А в теле процедур использую Clear. Ведь если кнопка сохранить (вторая процедура) нажата не будет, то список не очистится. А при повторном вызове первой процедуры, возникнет утечка памяти.
PM MAIL   Вверх
kami
Дата 4.4.2010, 16:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Цитата(uwannadie @  4.4.2010,  16:51 Найти цитируемый пост)
у меня в программе он единственный (по-крайней мере я больше не создавал)

Читай, пожалуйста, сообщения полностью. В частности:
Цитата(kami @  4.4.2010,  16:39 Найти цитируемый пост)
 Смотри ПОЛНЫЙ лог, найди в нем поиском сообщение о создании и не-высвобождении TStringList (будет дано всё, вплоть до конкретной строчки модуля). Оттуда и плясать.

Если в логе идут только адреса, то нужно включить в опциях проекта Debug information и include TD32 debug Info. В D7 первая находится в закладке Compiler а вторая на закладке Linker. После этого сделать Build проекту, удалить старый лог и запустить программу для генерации нового.

Добавлено через 1 минуту и 7 секунд
Цитата(Dom @  4.4.2010,  16:55 Найти цитируемый пост)
В целом немного необычно,

+много необычно smile
PM MAIL WWW   Вверх
uwannadie
Дата 4.4.2010, 17:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



нашел, на что ругается FastMM
есть у меня процедура, в которой содержимое дерева сохраняется в список (какашками не кидаться за индуский код, т.к. это пре альфа-альфа-альфа версия программы)
Код

procedure TfrmCreateNewUpdate.SaveNodesToFile(pTree: TBaseVirtualTree; pNode: PVirtualNode; var NodeList: TStringList);
var
  FileData: PFileInfo;
  TempNode: PVirtualNode;
begin
  if pNode.ChildCount > 0 then
  begin
    TempNode := pNode.FirstChild;
    repeat
      begin
        if TempNode.ChildCount = 0 then
        begin
          FileData := pTree.GetNodeData(TempNode);
          NodeList.Add(FilePriorityToStringEx(FileData^.FilePriority) +
                       '|' + FileData^.FileName);
        end;
        SaveNodesToFile(pTree, TempNode, NodeList);
        TempNode := TempNode.NextSibling;
      end;
    until (TempNode = nil);
  end;
end;

ругается везде на:
Код

NodeList.Add(FilePriorityToStringEx(FileData^.FilePriority) + '|' + FileData^.FileName);
.....
SaveNodesToFile(pTree, TempNode, NodeList); 

остальные утечки, судя по номерам строк, завязаны на реализации механизма поиска файлов в делфи
--------------------
PM MAIL   Вверх
Dom
Дата 4.4.2010, 17:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Отлично. Теперь осталось корректно освободить память от NodeList. После этого какие-то утечки еще остаются?
PM MAIL   Вверх
uwannadie
Дата 4.4.2010, 17:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



память освобождается, но вне процедуры:
Код

FileList := TStringList.Create;
SaveNodesToFile(vtProjectFiles, vtProjectFiles.RootNode, FileList);
...
FileList.Free;


--------------------
PM MAIL   Вверх
kami
Дата 4.4.2010, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Это всё, что Вас просили показать?
Удачи Вам.
PM MAIL WWW   Вверх
uwannadie
Дата 4.4.2010, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



последовал совету Dom, вынеся создание стриглистов в событие OnCreate формы а освобождение памяти в событие OnClose. в итоге остались лишь проблемы с памятью, связанные с тем, что RAD studio видимо все переменные типа String приводит к UnicodeString для поддержки юникода.

kami,Dom  - спасибо за Ваше время и Ваши нервы, потраченные на решение проблемы.

Добавлено @ 19:12
вот нашел обьяснение утечкам памяти:
Код

Таким образом, присвоение типа UnicodeString типу AnsiString может привести к потере данных. 
То есть если строка UnicodeString содержит данные со старшими байтами, преобразование такой строки в 
строку AnsiString приведет к потере старших байтов данных. 

© http://www.citforum.ru/programming/delphi/unicode/1.shtml

Это сообщение отредактировал(а) uwannadie - 4.4.2010, 19:14
--------------------
PM MAIL   Вверх
kami
Дата 4.4.2010, 19:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Цитата(uwannadie @  4.4.2010,  19:09 Найти цитируемый пост)
в итоге остались лишь проблемы с памятью, связанные с тем, что RAD studio видимо все переменные типа String приводит к UnicodeString для поддержки юникода.

Т.е. FastMM продолжает выдавать утечки?
В таком случае - проблема решена не полностью. В отлаженном приложении утечек быть не будет. Исключение я знаю только одно - в 9-й версии Indy была проблема с не-высвобождением чего-то из "внутренностей". При использовании стандартных компонент (VT можно отнести к ним) утечек быть не должно. Если есть - проблема в своем коде.

Лог после исправления части утечек в студию, пожалуйста.
PM MAIL WWW   Вверх
uwannadie
Дата 4.4.2010, 19:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



ругается постоянно на 2 строчки в процедуре

Код

procedure TfrmCreateNewUpdate.FillTreeviewWithFiles(directory: string; pTree: TVirtualStringTree; pNode: PVirtualNode);
var
  Mysearch: TSearchRec;
  FldrNode: PVirtualNode;
  FileData: PFileInfo;
begin
  if directory[Length(directory)] <> '\' then
    directory := directory + '\';
  pTree.BeginUpdate;
  if FindFirst(directory + '*.*', faDirectory, Mysearch) = 0 then
  begin
    repeat
      //поиск папок
      if ((Mysearch.Attr and faDirectory) = faDirectory) and (Mysearch.Name[1] <> '.') then
      begin
        if (Mysearch.Attr and faDirectory > 0) then
        begin
          pNode := pTree.AddChild(pNode,nil);
          FileData := pTree.GetNodeData(pNode);
          if Assigned(FileData) then
          with FileData^ do
          begin
            FileName := Directory + Mysearch.Name;
            TreeName := Mysearch.Name;
            FilePriority := fpNormal;
            ImageIndex := 0;
          end;
        end;
        FldrNode := pNode.Parent;
        FillTreeviewWithFiles(directory + Mysearch.Name + '\', pTree, pNode);
        pNode := FldrNode;
      end;
    until FindNext(Mysearch) <> 0;
      FldrNode := pNode;
  if FindFirst(directory + '*.*', $23, Mysearch) = 0 then
  begin
    repeat
      //поиск файлов
      pNode := pTree.AddChild(FldrNode,nil);
      FileData := pTree.GetNodeData(pNode);
      if Assigned(FileData) then
      with FileData^ do
      begin
        FileName := Directory + Mysearch.Name; //<<<< тут ругается (328 строка в модуле)
        TreeName := Mysearch.Name;
        FilePriority := fpNormal;
        ImageIndex := 1;
      end;
    until FindNext(Mysearch) <> 0; //<<<<<тут ругается (333 строка в модуле)
  end;
  FindClose(Mysearch);
  end;
  pTree.EndUpdate;
end;

еще ругается на 1 строчку в модуле с реализацией потока
Код

procedure TBuildThread.Execute;
var
  i: Integer;
  SourcePath: String;
  DestinationPath: String;
  pList: TIniFile;
begin
  DeleteFile(PChar(DestinationFolder + '\update.txt'));
  pList := TIniFile.Create(DestinationFolder + '\update.txt');
  pList.WriteInteger('Updater','File Count', pFileList.Count - 1);
    Synchronize(SetTotalProgressMax);
    for i := 0 to pFileList.Count - 1 do
  begin
    if Terminated then Exit;
    pFilePath := Copy(pFileList.Strings[i],Pos('|', pFileList.Strings[i]) + 1 ,
                        Length(pFileList.Strings[i]) - Pos('|', pFileList.Strings[i]));
    SourcePath := SourceFolder + pFilePath;
    DestinationPath := DestinationFolder + '\Updates' + ExtractDiffPath(pSourceFolder, pFilePath);
    pFileHash := IntToHex(FileCRC64(pFilePath), 16);
    Synchronize(UpdateCaption);
    pCriticalSection := Copy(pFileList.Strings[i], 0, Pos('|', pFileList.Strings[i]) - 1); // <<< тут ругается (136 строчка в модуле)
    pFileSize := GetFileSizeEx(pFilePath);
    pList.WriteString('File' + IntToStr(i),'Path',ExtractDiffPath(pSourceFolder, pFilePath));
    pList.WriteString('File' + IntToStr(i),'Url', ChangeSeparator('\Updates' + ExtractDiffPath(pSourceFolder, pFilePath)));
    pList.WriteString('File' + IntToStr(i),'Priority', pCriticalSection);
    pList.WriteInteger('File' + IntToStr(i),'Size', pFileSize);
    pList.WriteString('File' + IntToStr(i),'Hash', pFileHash);
    ForceDirectories(ExtractFilePath(DestinationPath));
    CompressFile(pFilePath, DestinationPath + '.bz2');
    pTotalProgress := i;
    Synchronize(UpdateTotalProgress);
  end;
  pFilePath := '';
  Synchronize(UpdateCaption);
  Synchronize(SetTotalProgressMax);
  pList.Free;
  Synchronize(UpdateControlsState);
end;

прикрепил лог работы 

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  UpdateManager_MemoryManager_EventLog.rar 43,17 Kb
--------------------
PM MAIL   Вверх
kami
Дата 4.4.2010, 19:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



В OnFreeNode вместо Finalize(FileData^) поставьте Dispose(FileData). по результатам будем смотреть дальше, но Finalize не предназначено для корректного высвобождения строк.
PM MAIL WWW   Вверх
uwannadie
Дата 4.4.2010, 20:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



пробовал уже давно, вылезает "Exception: Invalid Pointer Operation"
--------------------
PM MAIL   Вверх
kami
Дата 4.4.2010, 20:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Цитата(uwannadie @  4.4.2010,  20:00 Найти цитируемый пост)
пробовал уже давно, вылезает "Exception: Invalid Pointer Operation"

Понятно, ведь New не было вызвано, а они работают только в связке...
Сделайте так (в FillTreeviewWithFiles), Dispose оставьте на месте:
Код

New(FileData);
pNode:=pTree.AddChild(pNode, FileData);

// возможно, GetNodeData следующей строкой будет нужно, не помню, а делать тестовый проект неохота :)
if Assigned(FileData) then
  with FileData^ do
     begin
       FileName := Directory + Mysearch.Name;
       TreeName := Mysearch.Name;
       FilePriority := fpNormal;
       ImageIndex := 0;
.....



Это сообщение отредактировал(а) kami - 4.4.2010, 20:20
PM MAIL WWW   Вверх
uwannadie
Дата 4.4.2010, 20:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



все равно вылетает исключение
--------------------
PM MAIL   Вверх
Dom
Дата 4.4.2010, 20:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Немного не по теме
Цитата(kami @  4.4.2010,  19:49 Найти цитируемый пост)
но Finalize не предназначено для корректного высвобождения строк. 

Почему, или это исключительно для UnicodeString? В хелпе Д7 написано:
Цитата

Finalize simply sets all long strings to empty and all variants and interfaces to Unassigned, thus properly releasing any memory that was referenced by the long strings and variants.

Сам использую эту процедуру, для AnsiString работает корректно, память освобождается, никаких утечек.
PM MAIL   Вверх
Dom
Дата 4.4.2010, 21:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



А теперь по теме.
Может дело все же не в освобождении памяти из-под записей в дереве, если ручное "затирание" строк не устраняет утечек?
PM MAIL   Вверх
uwannadie
Дата 4.4.2010, 21:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



надо еще будет попробовать откомпилить и протестировать в других версиях делфи/бдс, может в компиляторе дело
--------------------
PM MAIL   Вверх
kami
Дата 4.4.2010, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



По теме и не по теме:
Dom, согласен, туплю. (по поводу высвобождения строк).
uwannadie, 
Dom, 
Дело действительно не в бобине smile Все-таки пришлось сделать тестовый проект, больно зацепила задачка.
В итоге - проблема в связках FindFirst>FindNext>FindClose процедуры FillTreeviewWithFiles. Если говорить точнее - то при окончании цикла по директориям не вызывался FindClose, а сразу шел FindFirst по файлам. Ну и + FindClose должен вызываться не всегда, а при успешном вызове FindFirst (гы, справка рулит smile  )

UPD: то ли лыжи не едут, то ли не пойму - утечки опять появились. Сейчас будем править...

Это сообщение отредактировал(а) kami - 4.4.2010, 21:54
PM MAIL WWW   Вверх
Dom
Дата 4.4.2010, 22:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Опять же получается "не по теме".
Вот тоже собрал тестовый проект, но по другому случаю - на посмотреть как освобождаются данные из узлов.
Получил неожиданный результат. Процедура OnFreeNode вызывается только для тех узлов, которые были видны на форме. И следовательно память из-под узлов которые не были видимы не освобождается. Если прокрутить список узлов до конца, то при вызове Clear освобождаются все узлы, и никаких утечек нет.
Э-э-э, в чем подвох?
Могу приложить тестовый проект, если требуется.
PM MAIL   Вверх
Dom
Дата 4.4.2010, 22:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Ага, заглянул в исходники. Чтобы вызвалась OnFreeNode должно выполнится условие
Код

[vsInitialized, vsInitialUserData] * Node.States <> []

Но при создании не все узлы получают vsInitialized.
А вот если после добавления всех узлов вызвать FullExpand, то память освобождается корректно без каких-либо дополнительных манипуляций. Т.е. инициализация происходит для всех узлов в этом случае.
PM MAIL   Вверх
uwannadie
Дата 4.4.2010, 22:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



эх, а я то думал, что у меня индусский код... 
пойду шаманить дальше...
--------------------
PM MAIL   Вверх
Dom
Дата 4.4.2010, 22:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Попробуй FullExpand вызвать для дерева, и потом сделай Clear. При этом дерево должно память освободить. И связанных с этим утечек памяти не будет.
Это конечно не очень красиво, но пока не пойму как иначе сделать.
PM MAIL   Вверх
kami
Дата 4.4.2010, 23:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 23
Всего: 72



Dom, точно!
Код

procedure TForm1.FillTreeviewWithFiles(directory: string;
  pTree: TVirtualStringTree; pNode: PVirtualNode);
var
  Mysearch: TSearchRec;
  FldrNode: PVirtualNode;
  FileData: PFileInfo;
begin
  Directory := IncludeTrailingPathDelimiter(Directory);
  if FindFirst(Directory + '*.*', faDirectory, Mysearch) = 0 then
    begin
      repeat
      //ïîèñê ïàïîê
        if ((Mysearch.Attr and faDirectory) = faDirectory) and (Mysearch.Name[1] <> '.') then
          begin
            pNode := pTree.AddChild(pNode, nil);
            FileData := pTree.GetNodeData(pNode);
            if Assigned(FileData) then
              begin
                FileData.FileName := Directory + Mysearch.Name;
                FileData.TreeName := Mysearch.Name;

                FileData.FilePriority := fpNormal;
                FileData.ImageIndex := 0;
                pNode.States := pNode.States + [vsInitialized, vsInitialUserData]; // ключевой момент.
              end;
            FldrNode := pNode.Parent;
            FillTreeviewWithFiles(Directory + Mysearch.Name, pTree, pNode);
            pNode := FldrNode;
          end;
      until FindNext(Mysearch) <> 0;
      FindClose(Mysearch);
    end;

  FldrNode := pNode;
  if FindFirst(Directory + '*.*', $23, Mysearch) = 0 then
    begin
      repeat
        pNode := pTree.AddChild(FldrNode, nil);
        FileData := pTree.GetNodeData(pNode);
        if Assigned(FileData) then
          begin
            FileData.FileName := Directory + Mysearch.Name;

            FileData.TreeName := Mysearch.Name;

            FileData.FilePriority := fpNormal;
            FileData.ImageIndex := 1;

            pNode.States := pNode.States + [vsInitialized, vsInitialUserData];
          end;
      until FindNext(Mysearch) <> 0;
      FindClose(Mysearch);
    end;
end;


Утечек =0, проверено на папке C:\
PM MAIL WWW   Вверх
Dom
Дата 5.4.2010, 01:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



kami, да, работать будет. Но мне кажется что в таком красивом компоненте инициализация должна делаться как-то изящнее. Смотрел исходники, так пока и не увидел где и в какой момент добавляется состояние vsInitialized добавленному узлу, который отображается, видимо где-то при попытке вывести содержимое узла на экран он и инициализируется. Но суть не в этом, вопрос в том как правильно инициализировать узел?

И кстати если уже решать проблему в лоб, то достаточно добавить vsInitialized, состояние vsInitialUserData используется немного для других целей.
PM MAIL   Вверх
uwannadie
Дата 5.4.2010, 02:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

Репутация: нет
Всего: 1



ну если не ошибаюсь, то в мануалах по VT написано, что дочерние элементы в дерево рекомендуется добавлять через события
OnInitChildren, а метод AddChild не рекомендуется использовать.

Это сообщение отредактировал(а) uwannadie - 5.4.2010, 02:52
--------------------
PM MAIL   Вверх
Dom
Дата 5.4.2010, 09:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Точно! Тоже нашел про инициализацию и добавление узлов в дерево через RootNodeCount, OnInitNode, OnInitChildren. Красиво конечно.
Только тут могут возникнуть заморочки с динамическим добавлением данных в узел, т.е. в рассматриваемом случае надо генерировать записи на лету при первом обращении к узлу. Либо надо где-то хранить предварительно созданный и заполненный список/массив исходных записей, что уже само по себе не есть правильно, т.к. при инициализации придется копировать эти данные в дерево. Следовательно расход памяти возрастет.
PM MAIL   Вверх
Dom
Дата 5.4.2010, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 121
Регистрация: 7.8.2005

Репутация: 1
Всего: 4



Вот процедура для ручной инициализации узла и если надо его наследников - ReinitNode.
Так что если нет желания переходить на OnInitNode и OnInitChildren, то после заполнения узлов по AddChild, надо пробежаться по ним всем и инициализировать этой процедурой. И тогда утечек не будет.
PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0903 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.