Как уже упоминалось в комментариях @kami, EHeapException
имеет внутренний флаг AllowFree
, который по умолчанию имеет значение False, предотвращая освобождение экземпляров EHeapException
обработчиками исключений.
EOutOfResources
происходит от EOutOfMemory
, что, в свою очередь, происходит от EHeapException
.
В блоке SysUtils
есть 2 одноэлементных объекта типа EOutOfMemory
и EInvalidPointer
. Всякий раз, когда RTL напрямую вызывает эти два указанных c типа исключения, он каждый раз вызывает один и тот же экземпляр этих классов. Поэтому у них есть флаг AllowFree
, чтобы обработчики исключений не освобождали синглтоны. Синглтоны освобождаются, когда устройство SysUtils
завершено.
Это фактически задокументированное поведение:
http://docwiki.embarcadero.com/Libraries/en/System.SysUtils.EHeapException
Примечание : Память для этих исключений предварительно выделяется при каждом запуске приложения и остается распределенной, пока приложение работает. Никогда не поднимайте EHeapException
или его потомков напрямую.
http://docwiki.embarcadero.com/Libraries/en/System.SysUtils.EOutOfMemory
Память для исключения EOutOfMemory
назначается заранее при каждом запуске приложения и остается распределенным до тех пор, пока приложение работает.
Примечание. Никогда не повышайте EOutOfMemory
напрямую. Вместо этого вызовите глобальную OutOfMemoryError
процедуру.
Однако, хотя EOutOfResources
является производным от EHeapException
, он никогда не используется однозначно, поэтому его флаг AllowFree
действительно никогда не должен быть Ложь. Поэтому мне кажется, что здесь есть несколько ошибок:
EOutOfResources
на самом деле не является кучей ошибок и не должны были быть получены из EHeapException
с самого начала. Это на самом деле распространенное исключение, например, модуль Vcl.Graphics
вызывает EOutOfResources
для некоторых из своих ошибок GDI, которые не имеют ничего общего с кучей.
EOutOfResources
имеет флаг AllowFree
установлен в False, когда вместо него должно быть значение True. И флаг private
, поэтому он не может быть перезаписан кроме как блоком SysUtils
, который делает это только для 2 синглетонов во время финализации. Таким образом,
синглтоны, как и все другие экземпляры-потомки, не передаются в RTL. RegisterExpectedMemoryLeak()
функция, когда AllowFree
имеет значение False, поэтому их можно исключить из отчетов об утечках.
Эта проблема утечки существует с Delphi 5 и уже была сообщена Embarcadero:
RSP-17193: утечка памяти EOutOfResources
RSP-19737: исключение EOutOfResources вызывает утечку памяти