Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.144.212.145] |
|
Страницы: (3) [1] 2 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Детский вопрос: имеется объект - наследник TObject
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 if BigMap = nil then begin BigMap:= TObjectList.Create(True); BigMap.Add(Map); end else BigMap.Add(Map); при необходимости удаления 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; все делает, но память не освобождает. В чем может быть проблема? |
Сообщ.
#2
,
|
|
|
>все делает, но память не освобождает.
Деструктор TMap вызывается? Перекрытия Destroy я не вижу, а кто будет ListOfObjects оcвобождать? |
Сообщ.
#3
,
|
|
|
А разве он не вызывается автоматически?
|
Сообщ.
#4
,
|
|
|
Вызывается деструктор TObject, который освобождает память, записанную в InstanceSize, финализирует динамические поля. Но про внутренние объекты он ничего не знает.
Нужно объявить и реализовать перекрытый (override) деструктор, в котором освободить то, что создавал вручную (и не забыть inherited) |
Сообщ.
#5
,
|
|
|
Ок, добавил destructor TMap.Destroy; override;
destructor TMap.Destroy; begin GeodeticLimits.Free; PlaneLimits.Free; ListOfObjects.Clear; ListOfObjects.Free; inherited Destroy; end; Но результат тот же. |
Сообщ.
#6
,
|
|
|
Деструктор вызывается? Проверено?
В чём выражается "но память не освобождает"? ListOfObjects освобождает свои объекты? В общем, тут много неясного, без телепатии тяжко. |
Сообщ.
#7
,
|
|
|
Смотрю в отладчике - ничего не понятно: после удаления (Bimap.Delete(I)) ListOfObjects пустой, но указатель есть, его TList не nil, но пустой. В диспетчере задач видно, что сколько занято памяти, столько и осталось занятым после удаления...
|
Сообщ.
#8
,
|
|
|
> ListOfObjects пустой, но указатель есть
А он и не должен обнуляться. Есть процедура FreeAndNil, которой пользуются при необходимости иметь нулевую ссылку после уничтожения (замечу, что на объект может быть несколько ссылок, а обнулится только одна) Диспетчер задач - не всегда показатель. |
Сообщ.
#9
,
|
|
|
Цитата MBo @ > ListOfObjects пустой, но указатель есть Диспетчер задач - не всегда показатель. А как еще отслеживать память? Из-за утечек получаю outofmemory, причем, довольно скоро, потому что загружаемые и не удаленные карты по 100-200 Мб. По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов. И далее по иерархии своих классов. Я правильно понимаю? |
Сообщ.
#10
,
|
|
|
>А как еще отслеживать память?
Включить ReportMemoryLeaksOnShutdown http://www.gunsmoker.ru/2009/05/blog-post_24.html >По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов. Если есть внутренние объекты, созданные в твоём коде - да, иначе нет. О статических полях и данных с автоматическим управлением (строки, динамические массивы, если они не содержат объекты) заботиться не нужно. |
Сообщ.
#11
,
|
|
|
Спасибо, постараюсь разобраться
|
Сообщ.
#12
,
|
|
|
Цитата mnj @ все делает, но память не освобождает. В чем может быть проблема? У тебя код удаления карт в #1 какой-то странный - он удаляет из списка не все карты, на которые не попадает заданная точка, а только одну, первую попавшуюся (выход из цикла по первому Find = true) Цитата mnj @ По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов. В деструкторе нужно удалять\освобождать объекты (экземпляры классов), а также динамические структуры данных (указатели), выделенные функциями New, GetMem, AllocMem, ReallocMem (или функциями WinApi). Как уже было сказано, автоматически очищаются только строки, динамические массивы (не содержащие объектов и указателей), варианты и интерфейсы. Цитата mnj @ постараюсь разобраться В первую очередь обрати внимание на класс объекта карты (то, что хранится в ListOfObjects), поскольку эти объекты, по идее, и занимают основной объем карты в 100-200 Мб, о которых ты говоришь. Поэтому, если деструктор этого объекта что-то не удаляет, то отсюда и возникает большая утечка памяти. Цитата mnj @ А как еще отслеживать память? Кроме ReportMemoryLeaksOnShutdown можно проверить освобождение памяти в конкретных местах вставкой вызовов функций GetMemoryManagerState или GetHeapStatus (она хоть и deprecated, но проще в использовании, чем GetMemoryManagerState). |
Сообщ.
#13
,
|
|
|
Прежде всего - спасибо за внимание к моей проблеме. Теперь по порядку:
Цитата leo @ У тебя код удаления карт в #1 какой-то странный - он удаляет из списка не все карты, на которые не попадает заданная точка, а только одну, первую попавшуюся (выход из цикла по первому Find = true) Все карты и не грузятся. Грузятся только те карты, на которые попадает точка в стартовой позиции, их м.б. 1, 2 или 3 штуки (я брал готовые, а они внахлест сделаны, с перекрытием друг друга, не как нормальные планшеты), поэтому по мере продвижения точка может покинуть только 1 карту. Про деструктор: Вот у меня создан простейший класс, от которого ползет все: TMyPoint = class Lon: real; //долгота Lat: real; //широта //destructor Destroy; override; end; Нужен ли ему свой конструктор и свой деструктор, если он прямой наследник TObject и отличается только наличием двух статических полей? В отладчике видно, что он создается без собственного конструктора и без проблем со всеми своими полями, а вот удалить его с деструктором или без него не получается, в отладчике он по-прежнему жив-здоров, если удалять экземпляр проcтым Free, а не FreeAndNil. Получается, что деструктор ему не нужен вовсе. destructor TMyPoint.Destroy; begin inherited Destroy; end; Что еще можно написать для него, если деструктор у предка - пустой. А вот его родственник: //треугольник 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 не обойтись: 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 |
Сообщ.
#14
,
|
|
|
> в отладчике он по-прежнему жив-здоров, если удалять экземпляр проcтым Free, а не FreeAndNil.
Что значит - жив-здоров? Указатель без обнуления указывает всё туда же, но его участок памяти помечен как свободный, очищать его ни к чему. >Получается, что деструктор ему не нужен вовсе. Такому классу переписывать деструктор не нужно, как я уже говорил. Более того, и класс здесь не нужен, если не предусматривается наследование-расширение, так как никакой функциональности или инкапсуляции он не реализует. Просто массив или запись. > if Assigned (Self.Vertexes[I]) then Self.Vertexes[I].Free; Проверка здесь ни к чему. Free само разберётся, нулевой указатель освобождать не станет |
Сообщ.
#15
,
|
|
|
Цитата MBo @ Что значит - жив-здоров? Указатель без обнуления указывает всё туда же, но его участок памяти помечен как свободный, очищать его ни к чему. Жив-здоров - это после выполнения Free можно по-прежнему присвоить значение полю объекта как вполне существующему, значит он продолжает жить и память не освобождает. Но мне нужно убить его совсем. Класс для точки - конечно, жирно. Это я от лени. Правильно было бы PPointRecord = ^TPointRecord; //точка TPointRecord = record Lat: real; Lon: real; end; |