Blog. Just Blog

Получение размера динамической памяти приложения (Heap)

05.09.2022 | Категория: Образ мышления: Assembler | Автор: ManHunter
Heap или куча - особая структура данных, с помощью которой приложению выделяется динамически распределяемая память. Крайне удобная штука, когда надо быстренько выделить немного памяти под сиюминутные нужды. Но при активной работе с кучей может возникнуть ситуация, когда надо узнать размер оставшейся памяти, общий размер кучи или максимальный размер непрерывных данных, которые туда можно записать. Что-то из этого можно узнать при помощи штатных функций, а что-то придется получать копанием в недрах системы. Но сперва несколько структур и констант для работы. Их нет даже в MSDN, не говоря уже о FASM.
  1. struct DEBUG_BUFFER
  2.         SectionHandle        dd ?
  3.         SectionBase          dd ?
  4.         RemoteSectionBase    dd ?
  5.         SectionBaseDelta     dd ?
  6.         EventPairHandle      dd ?
  7.         Unknown              rd 2
  8.         RemoteThreadHandle   dd ?
  9.         InfoClassMask        dd ?
  10.         SizeOfInfo           dd ?
  11.         AllocatedSize        dd ?
  12.         SectionSize          dd ?
  13.         ModuleInformation    dd ?
  14.         BackTraceInformation dd ?
  15.         HeapInformation      dd ?
  16.         LockInformation      dd ?
  17.         Reserved             rd 8
  18. ends
  19.  
  20. struct DEBUG_HEAP_INFORMATION
  21.         Base        dd ?
  22.         Flags       dd ?
  23.         Granularity dw ?
  24.         Unknown     dw ?
  25.         Allocated   dd ?
  26.         Committed   dd ?
  27.         TagCount    dd ?
  28.         BlockCount  dd ?
  29.         Reserved    rd 7
  30.         Tags        dd ?
  31.         Blocks      dd ?
  32. ends
  33.  
  34. PDI_HEAPS = 0x04
  35. PDI_HEAP_BLOCKS = 0x10
Каждый процесс может иметь больше одного объекта кучи, для получения данных об этих объектах воспользуемся недокументированной функцией RtlQueryProcessDebugInformation, предварительно подготовив буфер для приема данных еще одной недокументированной функцией RtlCreateQueryDebugBuffer. Указатель на интересующие нас данные содержится в поле HeapInformation структуры DEBUG_BUFFER. Это массив из нескольких структур типа DEBUG_HEAP_INFORMATION, каждая из которых соответствует одному из объектов кучи процесса. Перебирая их по очереди и сравнивая поле Base с искомым хэндлом, находим нужный объект. В следующем код предполагается, что в переменной hHeap содержится хэндл созданной кучи, по которой мы хотим получить информацию.
  1.         ; Зарезервировать буфер для отладочной информации
  2.         invoke  RtlCreateQueryDebugBuffer,0,FALSE
  3.         mov     [debug_buf],eax
  4.  
  5.         ; Получить информацию о кучах текущего процесса
  6.         invoke  GetCurrentProcessId
  7.         invoke  RtlQueryProcessDebugInformation,eax,\
  8.                 PDI_HEAPS+PDI_HEAP_BLOCKS,[debug_buf]
  9.         mov     eax,[debug_buf]
  10.         ; Указатель на информацию о кучах
  11.         mov     eax,[eax+DEBUG_BUFFER.HeapInformation]
  12.         ; Количество записей
  13.         mov     ecx,[eax]
  14.         ; Пропустить заголовок
  15.         add     eax,4
  16. .loc_heap_scan:
  17.         or      ecx,ecx
  18.         jz      .loc_heap_done
  19.  
  20.         ; Это наша куча?
  21.         mov     edx,[eax+DEBUG_HEAP_INFORMATION.Base]
  22.         cmp     edx,[hHeap]
  23.         jne     .loc_heap_next
  24.  
  25.         ...
  26.         ; В структуре DEBUG_HEAP_INFORMATION информация о куче
  27.         ...
  28.  
  29.         jmp     .loc_heap_done
  30.  
  31. .loc_heap_next:
  32.         add     eax,sizeof.DEBUG_HEAP_INFORMATION
  33.         dec     ecx
  34.         jmp     .loc_heap_scan
  35.  
  36. .loc_heap_done:
  37.         ; Прибраться за собой
  38.         invoke  RtlDestroyQueryDebugBuffer,[debug_buf]
Нужный объект кучи найден. Теперь давайте повнимательнее посмотрим на содержимое других полей структуры DEBUG_HEAP_INFORMATION. Запрошенный размер памяти Allocated - суммарный объем всех блоков, выделенных с помощью функции HeapAlloc. Committed - фактически выделенный размер памяти. Максимальный размер кучи Blocks - параметр dwMaximumSize, указанный при вызове функции HeapCreate и выровненный до размера страницы памяти. Размер страницы можно получить при помощи функции GetSystemInfo. BlockCount - количество выделенных блоков памяти в куче, оно может отличаться от количества вызовов функции HeapAlloc, так как содержит еще и служебные блоки. Также важно понимать, что из-за сегментации кучи размер блока, который можно разово выделить в ней, не обязательно равен разнице между значениями Blocks и Allocated. Для получения максимального размера непрерывного блока памяти надо воспользоваться функцией HeapCompact. В случае фрагментированной кучи эта функция вернет размер наибольшего свободного участка.

Читать статью целиком »
Просмотров: 1376 | Комментариев: 0

Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 1 (0.0161 сек.) / Память: 4.5 Mb
Наверх