В Windows 3.1 приложениях три специализированных области памяти занимают один (!) сегмент памяти объемом 64K: системная 'локальная куча' и два сегмента, содержащие все глобальные и инициализированные константы. Эта область памяти может быть израсходована очень быстро.
Вот почему W3.1 приложения практически -ничего- не хранят в куче или в глобальных переменных. Предпочтительно сохранение -указателей-. Вот объяснение того, почему в Delphi 'объект как указатель.'
В вашем случае рекомендую все большие глобальные переменные переместить в общий блок данных, который распределяет при запуске сама программа (как объект) и уничтожить их при выходе. Вы можете просмотреть содержимое сегмента данных, установив флажок 'linker map' в 'detailed' и просмотрев сегмент 'DATA'. Все данные, записываемые в данный участок памяти, пытаются расположиться в нижней части этого 64K-сегмента.
[000269]Я знаю, что это нелегкий способ, но я знаю что он будет работать, поскольку я делал это сам. Используйте DCC.EXE, компилируйте ваш полный проект (DPR) и добавляйте к командной строке опцию /GD, это позволит создать .MAP-файл. MAP-файл создан по правилам форматирования текстового файла, поэтому вы можете затем загрузить его в Delphi и там изучать.
Первая секция каждого MAP-файла включает в себя все модули, добавленные линковщиком в EXE-файл и размер этих модулей в HEX-байтах. Имя последнего модуля в списке - всегда DATA для сегментов данных. Здесь необходимо запомнить одну вещь - начальный адрес сегмента данных.
Следующая секция MAP-файла является листингом ВСЕХ Public-объявлений. Публичные объявления включают в себя переменные (например, TForm), возвращаемые величины и каждый объект, определенный в VCL. Наиболее важные здесь элементы списка - определения всех переменных в программе и насколько они большие (устанавливается косвенно).
Самый минимально-возможный проект Delphi создаст вам список из нескольких сотен записей.
Для нашего примера я использовал пустой проект, который Delphi создает вам автоматически: сохраните проект и модуль под любым именем каким вы хотите, закройте проект и выйдите из Delphi. Я использую имена DATAP.DPR и DATAU.PAS.
В DOS-строке введите следующую команду:
DCC DATAP.DPR /GD Теперь у вас будет скомпилированный проект и созданный файл DATAP.MAP. Снова загрузите Delphi и откройте в нем MAP-файл. Смотрим адрес сегмента DATA.
0008:0000 0E34H DATA DATA В нашем примере, как вы можете увидеть, VCL требует минимум $0E34 (3636) байт для сегмента данных (Data Segment). Теперь перейдем ко второй секции (ниже по тексту) и увидим начальные адреса вашего сегмента DATA.
0008:055A CreationControl 0008:055E VBXHook ....... .......... В любом проекте, который я когда-либо создавал, первые $0040 байт в MAP-файле всегда резервируются чем-то неопределенным. Вставляемая по умолчанию часть листинга всегда начинается с "CreationControl".
В проектах, где я имею хотя бы одно объявление TYPED CONST DATA, всегда указывается первый начальный адрес с отступом xxxx:0040 и перед "CreationControl", который, оказывается, сам занимает около 1300 байт.
Используя шестнадцатиричный адрес в качестве указателя, вы запросто можете вычислить разницу между распределенной памятью и памятью, реально занимаемую каждым элементом. Для этого понадобиться научный калькулятор, для этой цели подойдет калькулятор, поставляемый с Windows 3.0, только не забудьте переключить его в режим scientific (научный). Продолжаем: "встроенные" данные обычно начинаются с "CreationControl"/"HaltVector", который тут же сопровождается переменным указателем на вашу главную форму (4 байта).
0008:09DC HaltVector 0008:0A32 Form1 0008:0B60 NewStyleControls ....... .......... 0008:0D84 LongDayNames Все переменные для каждой формы приведены здесь в том же порядке, как они объявлены в модуле. Строка с "NewStyleControls" обычно знаменует конец секции с вашими переменными и начало остальных "встроенных" данных, которые, обычно, заканчиваются строкой "LongDayNames".
Я надесь что мое спутанное повествование не отпугнуло вас от дальнейшего изучения этого интересного вопроса, по крайней мере вы увидите своими глазами ваш проект "изнутри" и то, как Delphi "начиняет" EXE-файл данными из вашего проекта. Далее вы без труда можете найти место, где сегмент данных содержит по непонятной причине незаполненные области, хотя все это по-прежнему только в познавательных целях...
- Dennis Passmore [000832]