На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
Страницы: (3) [1] 2 3  все  ( Перейти к последнему сообщению )  
> Работа с TObjectList , Не освобождается память при удалении элемента-объекта из переменной типа TObjectList
    Детский вопрос: имеется объект - наследник TObject
    ExpandedWrap disabled
          TMap = class
           public
            Name: string;
            GeodeticLimits: TLimits;   //геодезические координаты в радианах
            PlaneLimits: TLimits;      //прямоугольные координаты
            NumberOfObjects: integer;  //количество объектов карты
            Units: byte;               //единицы измерения
            ListOfObjects: TObjectList;      //список объектов карты
            ErrorMsg: string;          //строка диагностики
            Loaded: boolean;           //загружена или нет
            constructor Create;
          end;

    набор карт хранится в глобальной переменной BigMap, которая имеет класс TObjectList
    var
    BigMap: TObjectList;

    при создании OwnsObjects указывается как True

    ExpandedWrap disabled
        if BigMap = nil then
                 begin
                    BigMap:= TObjectList.Create(True);
                    BigMap.Add(Map);
                 end
                 else BigMap.Add(Map);


    при необходимости удаления
    ExpandedWrap disabled
      var OnThere, Find: boolean;
          CurrentMap: TMap;
      .............
      begin
      ..................
          I:= 0;
          Find:= False;
              //проверка на попадание точки ВС в карту из списка загруженных
              repeat
                 CurrentMap:= TMap(BigMap.Items[I]) ;
                 OnThere:= IamThere(MyPlace, CurrentMap.PlaneLimits);
                 if IamThere(MyPlace, CurrentMap.PlaneLimits)=False then
                  begin
                     BigMap.Delete(I);  //удаляем, раз ВС не на карте
                     BigMap.Pack;       //упаковка
                     BigMap.Capacity:= BigMap.Count; //выравнивание по реальному счетчику
                     Find:= True;
                  end
                  else
                  inc(I);
              until (Find = True) or (I = BigMap.Count);
      .........
      end;

    все делает, но память не освобождает. В чем может быть проблема?
      >все делает, но память не освобождает.

      Деструктор TMap вызывается?
      Перекрытия Destroy я не вижу, а кто будет ListOfObjects оcвобождать?
      Сообщение отредактировано: MBo -
        А разве он не вызывается автоматически?
          Вызывается деструктор TObject, который освобождает память, записанную в InstanceSize, финализирует динамические поля. Но про внутренние объекты он ничего не знает.

          Нужно объявить и реализовать перекрытый (override) деструктор, в котором освободить то, что создавал вручную (и не забыть inherited)
            Ок, добавил destructor TMap.Destroy; override;
            ExpandedWrap disabled
              destructor TMap.Destroy;
              begin
                 GeodeticLimits.Free;
                 PlaneLimits.Free;
                 ListOfObjects.Clear;
                 ListOfObjects.Free;
                 inherited Destroy;
              end;

            Но результат тот же.
              Деструктор вызывается? Проверено?

              В чём выражается "но память не освобождает"?

              ListOfObjects освобождает свои объекты?

              В общем, тут много неясного, без телепатии тяжко.
              Сообщение отредактировано: MBo -
                Смотрю в отладчике - ничего не понятно: после удаления (Bimap.Delete(I)) ListOfObjects пустой, но указатель есть, его TList не nil, но пустой. В диспетчере задач видно, что сколько занято памяти, столько и осталось занятым после удаления...
                  > ListOfObjects пустой, но указатель есть
                  А он и не должен обнуляться.
                  Есть процедура FreeAndNil, которой пользуются при необходимости иметь нулевую ссылку после уничтожения (замечу, что на объект может быть несколько ссылок, а обнулится только одна)

                  Диспетчер задач - не всегда показатель.
                    Цитата MBo @

                    > ListOfObjects пустой, но указатель есть
                    Диспетчер задач - не всегда показатель.

                    А как еще отслеживать память?
                    Из-за утечек получаю outofmemory, причем, довольно скоро, потому что загружаемые и не удаленные карты по 100-200 Мб.
                    По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов. И далее по иерархии своих классов. Я правильно понимаю?
                      >А как еще отслеживать память?

                      Включить ReportMemoryLeaksOnShutdown

                      http://www.gunsmoker.ru/2009/05/blog-post_24.html

                      >По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов.

                      Если есть внутренние объекты, созданные в твоём коде - да, иначе нет.
                      О статических полях и данных с автоматическим управлением (строки, динамические массивы, если они не содержат объекты) заботиться не нужно.
                        Спасибо, постараюсь разобраться
                          Цитата mnj @
                          все делает, но память не освобождает. В чем может быть проблема?

                          У тебя код удаления карт в #1 какой-то странный - он удаляет из списка не все карты, на которые не попадает заданная точка, а только одну, первую попавшуюся (выход из цикла по первому Find = true)

                          Цитата mnj @
                          По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов.

                          В деструкторе нужно удалять\освобождать объекты (экземпляры классов), а также динамические структуры данных (указатели), выделенные функциями New, GetMem, AllocMem, ReallocMem (или функциями WinApi). Как уже было сказано, автоматически очищаются только строки, динамические массивы (не содержащие объектов и указателей), варианты и интерфейсы.

                          Цитата mnj @
                          постараюсь разобраться

                          В первую очередь обрати внимание на класс объекта карты (то, что хранится в ListOfObjects), поскольку эти объекты, по идее, и занимают основной объем карты в 100-200 Мб, о которых ты говоришь. Поэтому, если деструктор этого объекта что-то не удаляет, то отсюда и возникает большая утечка памяти.

                          Цитата mnj @
                          А как еще отслеживать память?

                          Кроме ReportMemoryLeaksOnShutdown можно проверить освобождение памяти в конкретных местах вставкой вызовов функций GetMemoryManagerState или GetHeapStatus (она хоть и deprecated, но проще в использовании, чем GetMemoryManagerState).
                            Прежде всего - спасибо за внимание к моей проблеме. Теперь по порядку:
                            Цитата leo @
                            У тебя код удаления карт в #1 какой-то странный - он удаляет из списка не все карты, на которые не попадает заданная точка, а только одну, первую попавшуюся (выход из цикла по первому Find = true)

                            Все карты и не грузятся. Грузятся только те карты, на которые попадает точка в стартовой позиции, их м.б. 1, 2 или 3 штуки (я брал готовые, а они внахлест сделаны, с перекрытием друг друга, не как нормальные планшеты), поэтому по мере продвижения точка может покинуть только 1 карту.
                            Про деструктор:
                            Вот у меня создан простейший класс, от которого ползет все:
                            ExpandedWrap disabled
                                  TMyPoint = class
                                    Lon: real;   //долгота
                                    Lat: real;   //широта
                                    //destructor Destroy; override;
                                  end;

                            Нужен ли ему свой конструктор и свой деструктор, если он прямой наследник TObject и отличается только наличием двух статических полей? В отладчике видно, что он создается без собственного конструктора и без проблем со всеми своими полями, а вот удалить его с деструктором или без него не получается, в отладчике он по-прежнему жив-здоров, если удалять экземпляр проcтым Free, а не FreeAndNil. Получается, что деструктор ему не нужен вовсе.
                            ExpandedWrap disabled
                              destructor TMyPoint.Destroy;
                              begin
                                inherited Destroy;
                              end;

                            Что еще можно написать для него, если деструктор у предка - пустой.

                            А вот его родственник:
                            ExpandedWrap disabled
                                //треугольник
                                TTriangle = class
                                  Vertexes: array [0..2] of TMyPoint;
                                  constructor Create;
                                  destructor Destroy; override;
                                end;
                              ....
                              constructor TTriangle.Create;
                              var I: integer;
                              begin
                                  for I := 0 to 2 do
                                  Self.Vertexes[I]:= TMyPoint.Create;
                              end;
                              destructor TTriangle.Destroy;
                              var I: integer;
                              begin
                                   for I := 0 to 2 do
                                   begin
                                      if Assigned (Self.Vertexes[I]) then Self.Vertexes[I].Free;
                                   end;
                                   inherited;
                              end;

                            Тем не менее
                            FastMM4 выдает такую штуку:
                            5CE4D6 [Types_classes.pas][Types_classes][TTriangle.$bctr$qqrv][389]
                            5D0B78 [main.pas][main][Triangulation$qqrp20System.Classes.TList][590]
                            5D0CF7 [main.pas][main][CreatePlane$qqrv][634]
                            5D11D1 [main.pas][main][TGLForm.FormCreate$qqrp14System.TObject][773]
                            The block is currently used for an object of class: TTriangle
                            От конструктора формы к процедуре рисования контура самолета (CreatePlane), потом к триангуляции и к треугольнику. Строка проблемного элемента - конструктор этого самого треугольника.
                            Или
                            5CDC92 [Types_classes.pas][Types_classes][TLimits.$bctr$qqrv][212]
                            5CE258 [Types_classes.pas][Types_classes][TMyFrame.$bctr$qqrv][349]
                            5D399A [main.pas][main][TGLForm.BuildFrames$qqrv][1466]
                            5D11EF [main.pas][main][TGLForm.FormCreate$qqrp14System.TObject][776]
                            The block is currently used for an object of class: TMyPoint
                            Тут все упирается в TLimits (габаритный контейнер карты), который тоже несложный, вроде и создается и умирает корректно, а TMyPoint, получается, палки в колеса ставит все равно, коли без freeandnil не обойтись:
                            ExpandedWrap disabled
                                  TLimits = class  //границы листа карты
                                    SW: TMyPoint;  //юго-западный угол
                                    NW: TMyPoint;  //северо-западный
                                    SE: TMyPoint;  //юго-восточный
                                    NE: TMyPoint;  //северо-восточный
                                    CoordSys: boolean;
                                    constructor Create;
                                    destructor Destroy; override;
                                  end;
                              ................
                              constructor TLimits.Create;
                              begin
                               // inherited Create;
                                SW:= TMyPoint.Create; //юго-запад
                                NW:= TMyPoint.Create; //северо-запад
                                SE:= TMyPoint.Create; //юго-восток
                                NE:= TMyPoint.Create; //северо-восток
                                CoordSys:= True;      //по умолчанию - прямоугольные координаты
                              end;
                               
                              destructor TLimits.Destroy;
                              begin
                                if Assigned(SW) then FreeAndNil(SW);
                                if Assigned(NW) then FreeAndNil(NW);
                                if Assigned(SE) then FreeAndNil(SE);
                                if Assigned(NE) then FreeAndNil(NE);
                                inherited;
                              end;


                            Где правда, если с TLimits есть проблема и в чем?
                            ПС - огромная утечка в функции тесселяции полигона при построении объекта карты, который отправляется в ListOfObjects, но это видно только в логе, FastMM говорит Unknown
                              > в отладчике он по-прежнему жив-здоров, если удалять экземпляр проcтым Free, а не FreeAndNil.

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

                              >Получается, что деструктор ему не нужен вовсе.

                              Такому классу переписывать деструктор не нужно, как я уже говорил. Более того, и класс здесь не нужен, если не предусматривается наследование-расширение, так как никакой функциональности или инкапсуляции он не реализует. Просто массив или запись.

                              > if Assigned (Self.Vertexes[I]) then Self.Vertexes[I].Free;

                              Проверка здесь ни к чему. Free само разберётся, нулевой указатель освобождать не станет
                              Сообщение отредактировано: MBo -
                                Цитата MBo @
                                Что значит - жив-здоров? Указатель без обнуления указывает всё туда же, но его участок памяти помечен как свободный, очищать его ни к чему.

                                Жив-здоров - это после выполнения Free можно по-прежнему присвоить значение полю объекта как вполне существующему, значит он продолжает жить и память не освобождает. Но мне нужно убить его совсем. Класс для точки - конечно, жирно. Это я от лени. Правильно было бы
                                ExpandedWrap disabled
                                    PPointRecord = ^TPointRecord;          //точка
                                    TPointRecord = record
                                      Lat: real;
                                      Lon: real;
                                    end;
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) [1] 2 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0650 ]   [ 17 queries used ]   [ Generated: 23.04.24, 22:29 GMT ]