Советы по Delphi

       

???? Слишком большой сегмент данных ???? I


Я получаю сообщение 'Data segment too large'. Что за проблема и как мне ее решить?

В 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]



Содержание раздела