Delphi освобождение памяти при закрытии формы

Обновлено: 30.06.2024

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

При закрытии приложения в Delphi 7 я получаю следующую ошибку: Инструкция по адресу 0x011c34a6 ссылается на память по адресу 0x018333f4. Память не могла быть прочитана. Есть идеи, что вызывает эту проблему ?

Всегда ли новая выделенная память освобождается при закрытии программы? (даже если неожиданно закрывается из-за ошибки / ошибки и т. д. или пользовательских функций закрытия)? Или он освобождает память только в том случае, если возвращается из main?

Это зависит от того, как вы объявили свой вектор.

  1. Если вы используете RAII (ваш вектор-это объект стека, std::vector<. > myVec; )
  2. Или если вы создали его в куче ( std::vector<. >* myVec = new std::vector<. >(); )

В первом случае вам ничего не придется делать, потому что как только вектор выйдет за пределы области видимости (что всегда происходит при завершении работы приложения), будет вызван его дескриптор и он очистит свои ressoruces.

Во втором случае вам придется вызвать delete myVec; , так что 1) вектор становится неинициализированным (так же, как и в первом случае, вызывается деструктор и т. д.) и 2) память вашего вектора освобождается.

Если вы просто объявите вектор, например.

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

Если вы использовали new , то вы должны использовать delete .

Если вы не создали его с помощью new (что, как правило, не следует делать), то вам не нужно ничего делать. Он будет уничтожен автоматически в соответствии с окончанием его срока службы, и деструктор автоматически освободит его память.

Если вы создали его с помощью new , то для хорошего порядка вам следует убедиться, что вы удалили его до завершения программы. Если вы этого не сделаете, то большинство современных операционных систем все равно освободят память; но если допустить ее утечку, это может затруднить отслеживание проблемных утечек и вызвать проблемы в экзотических операционных системах.

В любом случае, нет никакой необходимости очищать его; деструктор сделает это за вас.

Ваш вопрос касается двух разных вещей. OS и срок службы объекта в рамках программы

OS часть : вообще говоря, в современном OSes вам не нужно ничего делать. Любая приличная современная операционная система освобождает память после завершения процесса. Даже динамично allocated/requested.

Это одна из причин, почему windows 95 был настолько неисправен и нестабилен с течением времени. Но он этого не сделал. Таким образом, если приложение будет утекать из памяти (а приложения делали и делают это почти все время), оно будет заблокировано навсегда.

c++ : теперь, когда у вас есть современные контейнеры c++ и хорошо спроектированные и реализованные объекты, все они имеют написанные деструкторы. Поэтому они вежливы и милы, и они освобождают свою собственную память. И разрушаются они в основном при двух условиях. Если вы не выделяете его динамически, например, через new , компилятор знает, когда заканчивается срок службы объекта. Это выходит за рамки возможного. И он автоматически вызывает деструктор. Если вы используете new , вам нужно позвонить delete позже.

Так что ответ есть. Объект может очищаться после себя не только при закрытии приложения, но и при смерти объекта . Однако если вы утечете память, вы все равно должны быть в безопасности, и тогда процесс завершится.

Когда вы "close a program", операционная система несет ответственность за освобождение любой памяти, которую использовала программа. Независимо от того, как вы создали свой вектор, когда вы "close the program" вся память будет восстановлена. Вам не нужно ни о чем беспокоиться.

Однако в больших программах вы не должны полагаться на пользователя "closing the program", чтобы освободить используемую память. Если вы используете ключевое слово "new", вы несете ответственность за вызов "delete.", если вы объявили вектор без "new", вам не нужно ничего делать, так как деструктор автоматически обработает освобождение памяти для вас.

Гораздо чаще можно увидеть нечто подобное:

А не что-то вроде этого:

На самом деле, я никогда за свои 15 с лишним лет программирования не видел последнего. Последнее, на мой взгляд, разрушило бы цель контейнера STL. Я предполагаю, что кто-то все еще может заниматься программированием для windows 95, но это кажется крайне маловероятным. Самая распространенная проблема с любым контейнером STL-это когда у вас есть контейнер указателей. Поскольку контейнеры не могут быть гетерогенными, довольно часто можно увидеть или использовать контейнеры указателей на базовый, интерфейсный класс объектов. В этом случае вам придется выполнить цикл и удалить каждый объект, прежде чем стирать вещи из вектора. Если вектор потеряет область видимости, он не будет знать, как удалить объекты, на которые он указывает. Это только очистит память для указателей, которые были добавлены.

Если вы делаете следующее, в функции или в объявлении класса, то у вас нет никаких обязательств по очистке памяти. Реализация STL либо работает должным образом, либо нет. В любом случае, программист больше ничего не может сделать, кроме как определить свой собственный распределитель:

Я не собираюсь входить в boost или C++11, но FYI есть специальные типы контейнеров в boost, которые предназначены для облегчения использования контейнеров указателей. Я не уверен, что есть какие-то новые функции C++ 11, которые обеспечивают эту возможность. Лично я бы рекомендовал вам не беспокоиться о том, будет ли OSs делать правильные вещи, когда программа утечка памяти. Не пропускайте память. Если вы работаете со встроенным OS, прочитайте документацию и убедитесь, что вы знаете, имеет ли его реализация STL какие-либо ограничения.

Похожие вопросы:

Таким образом, я получил свою программу prism/mvvm/mef, работающую хорошо, пользователь вводит данные в приложение, а затем закрывает приложение (или выключает компьютер). Как я могу получить.

Я использую элемент управления webBrowser для открытия документа PDF в winforms, он работает нормально, но при закрытии приложения я иногда получаю ошибку : инструкция в 0x2d864aa2 ссылается на.

Необходимо ли выпускать объекты при выходе/закрытии программы? Другими словами, предположим, что у вас есть кнопка, которая закрывает ваше приложение, но прямо перед закрытием вы показываете.

При закрытии приложения в Delphi 7 я получаю следующую ошибку: Инструкция по адресу 0x011c34a6 ссылается на память по адресу 0x018333f4. Память не могла быть прочитана. Есть идеи, что вызывает эту.

Всегда ли новая выделенная память освобождается при закрытии программы? (даже если неожиданно закрывается из-за ошибки / ошибки и т. д. или пользовательских функций закрытия)? Или он освобождает.

Когда я закрываю свою программу во время отладки своей программы OSX, я получаю AccessViolation. Он разбивается на следующие точки: в System.internals.ExcUtils procedure.

Большинство, если не все, микроконтроллеры имеют векторную таблицу для всех исключений, которые встречаются при запуске программы. Я совершенно запутался в том,есть ли у загрузчика также своя.

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

Есть две формы (первая создается автоматически, вторая - "вручную"). После закрытия второй формы память не освобождается, нашёл в гугле такой пример:
Форма 1

Проблема в том, что в программе, скомпилированной на Delphi 7 все работает нормально, память освобождается, а на XE2 - нет

Присоединённый файл ( Кол-во скачиваний: 3 )
FormClose.rar 670,53 Kb

Репутация: 36
Всего: 63

У меня всё освобождается. А что именно не освобождается? Поробуйте включить в файл проекта ReportMemoryLeaksOnShutdown :

Код

program Project1;


У меня на XE2 при 32/64 всё хорошо, утечек никаких нету.
В мире всего две бесконечности: вселенная и человеческая глупость. На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5

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

При открытии второй формы потребляемая программой память возрастает. При закрытии - должна освобождаться. Но на ХЕ2 например, как было 1300 Кб после открытия второй формы так и осталось после её уничтожения. caFree - ведь должно освобождать память при закрытии?

Репутация: 36
Всего: 63

Она и освобождается, просто Вы не то меряете и не тем. Скорее всего Вы меряете по диспетчеру задач, который показывает вообще виртуальную память процесса, а не физическое использование памяти.
В мире всего две бесконечности: вселенная и человеческая глупость. На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5

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

А что и чем мерять? И почему тогда при закрытии второй формы в скомпилированной на D7 программы используемая память (которая отобр. в дисп. задач) уменьшается, а на ХЕ2 не меняется? программы ведут себя по разному?

Репутация: 36
Всего: 63

Ну как минимум Process Explorer показывает более детальную информацию в разделе Perfomance.
Различие между Delphi7/XE2 в абсолютно разном менеджере памяти - новые делфи используют FastMM, вероятно новый менеджер памяти не выделяет физическую память т.к. высвободилось совсем немного (это очень затратная по ресурсам операция). Думаю, высвобождение будет заметно при больших объёмах памяти.
В мире всего две бесконечности: вселенная и человеческая глупость. На счёт вселенной я не уверен.
Шифрование и организация фотографий - Photo Database 4.5

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

Цитата

Думаю, высвобождение будет заметно при больших объёмах памяти.

50 Мб). При закрытии формы память освободилась.


Я так и не нашёл его. А чем отличаются Private Bytes от Working Set? Private Bytes - это то, что показывает диспетчер задач (частный рабочий набор), да?

Репутация: 38
Всего: 89

naparNIK, почитай. Там всё написано - и почему так происходит, и чем мерять, и когда кричать караул, а когда - не надо.
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.

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

вообще , встроенный менеджер памяти не всегда отдает память системе, когда ты ее освобождаешь. У него есть свой кэш. Это если речь о небольшом блоке.

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

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

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

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

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

Но не вызовет ли этот код конфликтных ситуаций? Ведь по сути получится, что выход из функции класса TForm2::FormClose() произойдет уже после того, как сам класс будет уничтожен.

Собственно два вопроса: корректен ли такой способ удаления объекта формы? Если нет, то как это правильно делать?

Есть некий класс формы. Создается динамически.
Задача: очистить выделенную память после закрытия формы. Как оказалось, по закрытию форма не вызывает своего деструктора.
Собственно как корректно заставить форму освобождать память при закрытии?
Первой идеей было поместить в обработчик события OnClose, следующую строчку:
void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
delete this;
>

Но не вызовет ли этот код конфликтных ситуаций? Ведь по сути получится, что выход из функции класса TForm2::FormClose() произойдет уже после того, как сам класс будет уничтожен.

Собственно два вопроса: корректен ли такой способ удаления объекта формы? Если нет, то как это правильно делать?

как форма отображается? (модально али нет)
если модально то


иначе удалять принудительно когда она больше не нужна в классе, который ее создал и вызвал (можно при помощи некоего флага)
т.е.

TForm2();
а вообще, Form2->Free() - освобобождает и так память.
вот пример динамического создания:

TForm2();
а вообще, Form2->Free() - освобобождает и так память.
вот пример динамического создания:

а что деструктор формы делает? (я всегда думал что он атоматом вызывается при уничтожении объекта)
как его сюда приваять не вижу возможностей (разве только lkz удаления дочерних объектов)
метод Free() - это паскалевская конструкция, в С++ не прокатит, для этого есть delete

а что деструктор формы делает? (я всегда думал что он атоматом вызывается при уничтожении объекта)
как его сюда приваять не вижу возможностей (разве только lkz удаления дочерних объектов)
метод Free() - это паскалевская конструкция, в С++ не прокатит, для этого есть delete

На счет деструктора, да, я ошибся.

delete - тоже прокатит. Но, если мне не изменяет память, Free() - не просто уничтожает объект, в отличии от delete.

На счет деструктора, да, я ошибся.

delete - тоже прокатит. Но, если мне не изменяет память, Free() - не просто уничтожает объект, в отличии от delete.

цитата прямо из хелпа:
[quote=BCB Help]
Do not call the Free method of an object. Instead, use the delete keyword, which invokes Free to destroy an object. Free automatically calls the destructor if the object reference is not NULL.
[/quote]

Есть некий класс формы. Создается динамически.
Задача: очистить выделенную память после закрытия формы. Как оказалось, по закрытию форма не вызывает своего деструктора.
Собственно как корректно заставить форму освобождать память при закрытии?
Первой идеей было поместить в обработчик события OnClose, следующую строчку:

void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
delete this;
>

Но не вызовет ли этот код конфликтных ситуаций? Ведь по сути получится, что выход из функции класса TForm2::FormClose() произойдет уже после того, как сам класс будет уничтожен.

Собственно два вопроса: корректен ли такой способ удаления объекта формы? Если нет, то как это правильно делать?


Нет не корректен. Подобный вызов делита однозначно приведет к проблемам.
Парвильно
Правильно:

function AllocMem(Size: Cardinal): Pointer;
Выделяет в куче блок памяти заданного размера. Каждый байт выделенной памяти выставляется в ноль. Для освобождения памяти используется FreeMem.

AllocMemCount

var AllocMemCount: Integer;
Содержит количество выделенных блок памяти. Эта переменная увеличивается каждый раз, когда пользователь запрашивает новый блок, и уменьшается, когда блок освобождается. Значения переменной используется для определения количества "оставшихся" блоков.

Так как переменная является глобальной и живёт в модуле System, её прямое использование не всегда безопасно. Модули, слинкованные статически, будут иметь разные экземпляры AllocMemCount. Статически слинкованными считаются приложения, не использующие пакеты времени выполнения (runtime packages). В следующей таблице обобщены сведения по использованию AllocMemCount в зависимости от типа приложения.

Тип приложенияДоступность AllocMemCount
EXEПриложения, не использующие пакеты и dll-и Delphi могут спокойно обращаться к данной глобальной переменной, т.к. для них существует только один её экземпляр.
EXE с пакетами без dllПриложения, использующие пакеты и не использующие dll-ки также могут спокойно работать с AllocMemCount. В этом случае все модули линкуются динамически, и существует только один экземпляр переменной, т.к. пакеты, в отличие от dll, умеют работать с глобальными переменными.
EXE со статически слинкованными dllЕсли приложение и используемые им dll-ки являются статически слинкованными с библиотекой выполнения (RTL), AllocMemCount никогда не следует использовать напрямую, т.к. и приложение, и dll-ки будут иметь собственные её экземпляры. Вместо этого следует использовать функцию GetAllocMemCount, живущую в BorlandMM, которая возвращает значение глобальной переменной AllocMemCount, объявленную в BorlandMM. Этот модуль отвечает за распределение памяти для всех модулей, в списке uses который первой указан модуль sharemem. Функция в данной ситуации используется потому, что глобальные переменные, объявленные в одной dll невидимы для другой.
EXE с пакетами и статически слинкованными dll-камиНе рекомендуется создавать смешанные приложения, использующие и пакеты, и статически слинкованные dll-ки. В этом случае следует с осторожностью работать с динамически выделяемой памятью, т.к. каждый модуль будет содержать собственный AllocMemCount , ссылающийся на память, выделенную и освобождённую именно данным модулем.

AllocMemSize

var AllocMemSize: Integer;
Содержит размер памяти, в байтах, всех блоков памяти, выделенных приложением. Фактически эта переменная показывает, сколько байтов памяти в данный момент использует приложение. Поскольку переменная является глобальной, то к ней относится всё, сказанное в отношении AllocMemCount.

GetHeapStatus
function GetHeapStatus: THeapStatus;
Возвращает текущее состояние диспетчера памяти.

type
THeapStatus = record
TotalAddrSpace: Cardinal;s
TotalUncommitted: Cardinal;
TotalCommitted: Cardinal;
TotalAllocated: Cardinal;
TotalFree: Cardinal;
FreeSmall: Cardinal;
FreeBig: Cardinal;
Unused: Cardinal;
Overhead: Cardinal;
HeapErrorCode: Cardinal;
end;
Если приложение не использует модуль ShareMem, то данные в записи TheapStatus относятся к глобальной куче (heap), в противном случае это могут быть данные о памяти, разделяемой несколькими процессами.
TotalAddrSpaceАдресное пространство, доступное вашей программе в байтах. Значение этого поля будет расти, по мере того, как увеличивается объём памяти, динамически выделяемый вашей программой.
TotalUncommittedПоказывает, сколько байтов из TotalAddrSpace не находятся в swap-файле.
TotalCommittedПоказывает, сколько байтов из TotalAddrSpace находятся в swap-файле. Соответственно, TotalCommited + TotalUncommited = TotalAddrSpace
TotalAllocatedСколько всего байтов памяти было динамически выделено вашей программой
TotalFreeСколько памяти (в байтах) доступно для выделения вашей программой. Если программа превышает это значение, и виртуальной памяти для этого достаточно, ОС автоматом увеличит адресное пространство для вашего приложения и соответственно увеличится значения TotalAddrSpace
FreeSmallДоступная, но неиспользуемая память (в байтах), находящаяся в "маленьких" блоках.
FreeBigДоступная, но неиспользуемая память (в байтах), находящаяся в "больших" блоках. Большие блоки могут формироваться из непрерывных последовательностей "маленьких".
UnusedПамять (в байтах) никогда не выделявшаяся (но доступная) вашей программой. Unused + FreeSmall + FreeBig = TotalFree.
OverheadСколько памяти (в байтах) необходимо менеджеру кучи, чтобы обслуживать все блоки, динамически выделяемые вашей программой.
HeapErrorCodeВнутренний статус кучи

Учтите, что TotalAddrSpace, TotalUncommitted и TotalCommitted относятся к памяти ОС, выделяемой для вашей программы, а TotalAllocated и TotalFree относятся к памяти кучи, используемой для динамического выделения памяти самой программой. Таким образом, для отслеживания того, как ваша программа использует динамическую память, используйте TotalAllocated и TotalFree. Константы для HeapErrorCode живут в MEMORY.INC (highly recommended для всех продвинутых и интересующихся). За компанию приведём и их.

КодКонстантаЗначение
0cHeapOkВсё отлично
1cReleaseErrОС вернула ошибку при попытке освободить память
2cDecommitErrОС вернула ошибку при попытке освободить память, выделенную в swap-файле
3cBadCommittedListСписок блоков, выделенных в swap-файле, выглядит подозрительно
4cBadFiller1Хреновый филлер. (Ставлю пиво тому, кто объяснит мне, что это значит). Судя по коду в MEMORY.INC, значения выставляются в функции FillerSizeBeforeGap, которая вызывается при различного рода коммитах (т.е. при сливании выделенной памяти в swap). И если что-то в этих сливаниях не срабатывает, функция взводит один из этих трёх флагов.
5cBadFiller2"-/-"
6cBadFiller3"-/-"
7cBadCurAllocЧто-то не так с текущей зоной выделения памяти

8cCantInitНе вышло инициализироваться
9cBadUsedBlockИспользуемый блок памяти нездоров
10cBadPrevBlockПредыдущий перед используемым блок нездоров
11cBadNextBlockСледующий после используемого блок нездоров
12cBadFreeListХреновый список свободных блоков. Судя по коду, речь идёт о нарушении последовательности свободных блоков в памяти
13cBadFreeBlockЧто-то не так со свободным блоком памяти
14cBadBalanceСписок свободных блоков не соответствует действительности

GetMemoryManager

procedure GetMemoryManager(var MemMgr: TMemoryManager);
Возвращает указатель на текущий диспетчер памяти. Структура TMemoryManager описана ниже.
TMemoryManager - структура данных

type
PMemoryManager = ^TMemoryManager;

TMemoryManager = record
GetMem: function(Size: Integer): Pointer;
FreeMem: function(P: Pointer): Integer;
ReallocMem: function(P: Pointer; Size: Integer): Pointer;
end;

Эта запись определяет, какие функции используются для выделения и освобождения памяти. Функция GetMem должна выделить блок памяти размером Size (Size никогда не может быть равным нулю) и вернуть на него указатель. Если она не может этого сделать, она должна вернуть nil. Функция FreeMem должна освободить память Size по адресу P. P никогда не должен быть равен nil. Если функция с этим справилась, она должна вернуть ноль. Функция ReallocMem должна перевыделить память Size для блока P. Здесь P не может быть nil и Size не может быть 0 (хотя при вызове ReallocMem не из диспетчера памяти, это вполне допускается). Функция должна выделить память, при необходимости, переместить блок на новое место и вернуть указатель на это место. Если выделение памяти невозможно, она должна вернуть nil.

HeapAllocFlags

var HeapAllocFlags: Word = 2;
Этими флагами руководствуется диспетчер памяти при работе с памятью. Они могут комбинироваться и принимать следующие значения (по умолчанию - GMEM_MOVEABLE):

ФлагЗначение
GMEM_FIXEDВыделяет фиксированную память. Т.к. ОС не может перемещать блоки памяти, то и нет нужды блокировать память (соответственно, не может комбинироваться с GMEM_MOVEABLE)
GMEM_MOVEABLEВыделяет перемещаемую память. В Win32 блоки не могут быть перемещены, Если они расположены в физической памяти, но могут перемещаться в пределах кучи.
GMEM_ZEROINITПри выделении памяти (например, функцией GetMem) все байты этой памяти будут выставлены в 0. (отличная черта)
GMEM_MODIFY Используется для изменения атрибутов уже выделенного блока памяти
GMEM_DDESHAREВведёны для совместимости с 16-разрядными версиями, но может использоваться для оптимизации DDE операций. Собственно, кроме как для таких операций эти флаги и не должны использоваться
GMEM_SHARE"-/-"
GPTRПредустановленный, соответствует GMEM_FIXED + GMEM_ZEROINIT
GHNDПредустановленный, соответствует GMEM_MOVEABLE + GMEM_ZEROINIT

IsMemoryManagerSet

function IsMemoryManagerSet:Boolean;
Возвращает TRUE, если кто-то успел похерить дефолтовый диспетчер памяти и воткнуть вместо него свой.

procedure ReallocMem(var P: Pointer; Size: Integer);
Перевыделяет память, ранее выделенную под P. Реальные действия процедуры зависят от значений P и Size.
P = nil, Size = 0: ничего не делается;
P = nil, Size <> 0: соответствует вызову P := GetMem (Size);
P <> nil, Size = 0: соответствует вызову FreeMem (P, Size) (с тем отличием, что FreeMem не будет обнулять указатель, а здесь он уже равен nil).
P <> nil, Size <> 0: перевыделяет для указателя P память размером Size. Текущие данные никак не затрагиваются, но если размер блока увеличивается, новая порция памяти будет содержать всякий мусор. Если новый блок "не влазит" на своё старое место, он перемещается на новое место в куче и значение P обновляется соответственно. Это важно: после вызова данной процедуры блок P может оказаться в памяти по совсем другому адресу!

SetMemoryManager

procedure SetMemoryManager(const MemMgr: TMemoryManager);
Устанавливает новый диспетчер памяти. Он будет использоваться при выделении и освобождении памяти процедурами GetMem, FreeMem, ReallocMem, New и Dispose, а также при работе конструкторов и деструкторов объектов и работе с динамическими строками и массивами.
SysFreeMem, SysGetMem, SysReallocMem
Используются при написании собственного диспетчера памяти. Другого смысла в них я не нашёл.

Думаете, очень сложно? Как бы не так. Вот пример из справочной системы самой Delphi: этот диспетчер будет запоминать количество выделений, освобождений и перевыделений памяти:

var
GetMemCount: Integer;
FreeMemCount: Integer;
ReallocMemCount: Integer;
OldMemMgr: TMemoryManager;

function NewGetMem(Size: Integer): Pointer;
begin
Inc(GetMemCount);
Result := OldMemMgr.GetMem(Size);
end;

function NewFreeMem(P: Pointer): Integer;
begin
Inc(FreeMemCount);
Result := OldMemMgr.FreeMem(P);
end;

function NewReallocMem(P: Pointer; Size: Integer): Pointer;
begin

Inc(ReallocMemCount);
Result := OldMemMgr.ReallocMem(P, Size);
end;

const
NewMemMgr: TMemoryManager = (
GetMem: NewGetMem;
FreeMem: NewFreeMem;
ReallocMem: NewReallocMem);

procedure SetNewMemMgr;
begin
GetMemoryManager(OldMemMgr);
SetMemoryManager(NewMemMgr);
end;

Доброго времени суток.
Пытаюсь разобраться с QMdiArea.
При создании subWindow все понятно, но не могу понять почему при закрытии subWindow не освобождается память.
Вот простой пример:

1.Как правильно и грамотно реализовать работу с QMdiArea?
2.При закрытие subWindow освободить память.
2.Как из формы listDoc(форма списка документов) открыть саму форму документа (к примеру DocExample) в mdiArea?
Спасибо за понимание.

Рекомендуем хостинг TIMEWEB

Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Подписчики

метод removeSubWindow не гарантирует освобождения памяти.

вот описание метода

Removes widget from the MDI area. The widget must be either a QMdiSubWindow or a widget that is the internal widget of a subwindow. Note widget is never actually deleted by QMdiArea. If a QMdiSubWindow is passed in, its parent is set to nullptr and it is removed; but if an internal widget is passed in, the child widget is set to nullptr and the QMdiSubWindow is not removed.

Обратите внимание на следующее

Note widget is never actually deleted by QMdiArea.

Что переводится как,

Обратите внимание, что виджет никогда не удаляется QMdiArea .

Вам нужно вруную выполнять удаление этого виджета

Но меня напрягает то, что listDoc у вас объявлена как локальная переменная метода onOpenListDoc . То есть, если у вас этот код не падает, то предположу, что в заголовочном файле у вас есть ещё одна переменная с именем listDoc . Этот кусок должен быть написан иначе, без auto

И не используйте устаревший синтаксис сигналов и слотов через макросы SIGNAL SLOT, это ведёт к большому числу проблем. Используйте через указатели, как здесь

connect(listDoc, &ListDoc::closeListForm, this, &MainWindow::closeSubWindowsListDoc);

Спасибо за оперативный ответ.
С функциональными указателями не разобрался до конца. Как раз читаю New_Signal_Slot_Syntax
Да вы правы в заголовочном файле объявлена переменная listDoc

mainwindow.h

mainwindow.cpp

Не совсем понимаю когда будет удален виджет.
В случае с listDoc понятно, а в случае с DocExample не понятно когда будет удален (в какой момент).
Попробую описать последовательность действий:
1.Выделяем память под виджет DocExample для открытия (для пользователя док.№1)
2.Запись данных в БД SQLite
3.Закрытие формы виджета DocExample
4.Удаляем виджет:
5.Следующее открытие формы виджета DocExample (для пользователя док.№2) - выделение памяти

в описание метода deleteLater() :

The object will be deleted when control returns to the event loop

Объект будет удален, когда управление вернется в цикл обработки событий.

Насколько я понимаю при повторном открытии ( п.5 ) срабатывает метод

Есть ли возможность отследить метод deleteLater() ?

Если вы хотите понять, когда выполняется удаление объекта при использовании deleteLater() , то просто поставьте точку останова в деструкторе DocExample и пройдитесь в режиме отладки по программе, когда объект будет удалён, то вы сможете посмотреть стеку вызова функций и поймёте, когда сработало удаление объекта.

Я не совсем понял из вашего описания, в какой моменты вы вообще хотите создать виджет docExample

Читайте также: