Сколько памяти фактически было выделено из кучи для объекта? - PullRequest
4 голосов
/ 04 июня 2009

У меня есть программа, которая использует слишком много памяти для выделения множества маленьких объектов в куче. Поэтому я хотел бы изучить способы его оптимизации. Программа скомпилирована с Visual C ++ 7.

Есть ли способ определить, сколько памяти фактически выделено для данного объекта? Я имею в виду, когда я звоню new , куча выделяет не менее необходимой суммы. Как узнать, сколько именно было выделено?

Ответы [ 6 ]

9 голосов
/ 04 июня 2009

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

Вы можете приблизить это значение, выделив определенное количество элементов одинакового размера (скажем, 4096) и отметив разницу в используемой памяти. Разделив последнее на первое, вы получите ответ. Обратите внимание, что это значение изменяется от ОС к ОС, а также от версии ОС к версии ОС, и иногда отладочные сборки вашего приложения могут включать дополнительное отслеживание кучи, что увеличивает издержки. В некоторых ОС пользователи могут изменять политики кучи (т. Е. Использовать один распределитель кучи по сравнению с другим по умолчанию). Пример: Windows и pageheap.exe

Просто к сведению, куча по умолчанию (не LFH) в 32-битной Windows занимает:

  • sizeof (your_type), округленный до границы DWORD,
  • 3 указателя на предыдущий / следующий / размер
  • 2 указателя для файлов cookie безопасности
4 голосов
/ 04 июня 2009

Вы, вероятно, хотите перейти к модели пула памяти (о чем говорил предыдущий ответ о «распределении большого пула». Поскольку пулы памяти не требуют дополнительных затрат для каждого выделения, они предлагают экономию пространства для больших количеств маленьких объектов. Если время жизни группы этих маленьких объектов короткое (т.е. вы выделяете кучу маленьких объектов, то вам нужно избавиться от них), пул памяти также намного быстрее, потому что вы можете просто освободить пул вместо каждого объекта.

В Википедии есть некоторая информация о технике, а также ссылка на несколько реализаций:

http://en.wikipedia.org/wiki/Memory_pool

вы сможете найти другие реализации с помощью простого веб-поиска.

3 голосов
/ 04 июня 2009

Не наверняка, независимо от платформы. Я не помню никаких подробностей (за исключением ОС, которую я почти уверен, что вы не используете), но ваша ОС может предложить способ проверки «размера» выделенного распределения, и новые возможности могут используйте malloc или эквивалентный. Таким образом, вы можете получить то, что распределитель памяти считает размером выделения. Это может включать или не включать какой-либо заголовок, предшествующий выделению (вероятно, нет, я думаю).

Один из вариантов - выделить несколько миллионов маленьких объектов и посмотреть, сколько памяти использует ваша программа. Затем выделите еще несколько миллионов и посмотрите снова. Общее количество обычно увеличивается в виде кусков, поскольку процесс выделяет ОЗУ (или виртуальное адресное пространство) ОС, но при большом количестве объектов эффект этой «ошибки округления» будет обычно стремиться к 0 байтов на объект.

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

1 голос
/ 04 июня 2009

В Windows вы можете использовать структуры Heap32First и HEAPENTRY32 , чтобы определить размер любой данной записи кучи, если вы не используете настраиваемый менеджер кучи. Стоит также отметить, что размер выделенного блока в отладке может быть больше, чем в сборках выпуска из-за защитных байтов. Я не вижу упоминания о функциях Heap64 в MSDN, поэтому я предполагаю, что они просто используют имя Heap32.

1 голос
/ 04 июня 2009

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

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

0 голосов
/ 04 июня 2009

[РЕДАКТИРОВАТЬ] Этот ответ неверный! Я оставляю это как пример того, чего не следует делать. Оператор sizeof работает во время компиляции.


Вы пробовали:

SomeClass* some_instance = new SomeClass;
printf("Size of SomeClass == %u", sizeof(*some_instance) );

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...