Windows堆管理

Windows堆管理

Windows的堆管理器,负责管理使用页面粒度内存分配函数保留的大内存区中的内存分配。

这句话的意思是,堆是基于页粒度内存分配的更高级的内存管理策略。

"使用页面粒度内存分配函数保留的大内存区"指的是操作系统底层的内存管理单元。在 Windows 中,虚拟内存管理器以页(Page,通常为 4KB)为基本单位管理物理内存,并且通过 VirtualAlloc等函数分配内存时,实际上是以分配粒度(Allocation Granularity,通常为 64KB)​ 来保留地址空间的。这意味着,即使应用程序只申请 1 字节,VirtualAlloc也会为其保留至少 64KB 的地址空间,造成巨大的浪费。

堆管理器并不直接操作物理页,而是先通过 VirtualAlloc向系统"批发"一大块连续的虚拟地址空间(称为"堆段"或"堆块"),然后在这块"批发"来的大内存区内部,自行实现一套精细的分配、释放、合并算法,将内存"零售"给应用程序。这样,多个小内存申请可以共享同一个 64KB 的保留区域,极大地提升了内存利用率和地址空间效率。

在64位系统中,Windows堆管理器分配粒度最小为16字节。

NT堆

这是最通用的堆。NT堆分为前端和后端:

堆前端层

前端分配器是性能优化层,专为高频、小内存分配设计,核心目标是极速分配(O(1) 时间复杂度)​ 与低碎片。

  • 低碎片堆(Low-Fragmentation Heap, LFH):Windows XP SP2 后默认启用,是主要的前端实现。它将内存预切分为约 128 种固定大小的"桶"(Bucket),每个桶内块大小相同。申请时直接映射到对应桶,从空闲链表中取出第一块,几乎无计算开销。
  • 适用场景:对象大小 ≤ 16KB(默认阈值)且分配频率高(默认触发阈值约为 16 次连续分配)。

堆后端层

后端分配器是基础管理层,直接与虚拟内存管理器交互,负责堆段(Segment)的生命周期管理与大对象分配。

  • 堆段管理:通过 VirtualAlloc向系统申请大的连续地址空间(默认为 1MB),称为堆段。后端在其中维护空闲列表(Free Lists) 和位图(Bitmaps) 来跟踪块状态。
  • 分配策略:
    • 小块分配:在现有堆段中查找足够大的空闲块,可能进行分割(Split)以满足请求。
    • 大块分配:当单次申请超过 512KB(默认阈值) 时,直接调用 VirtualAlloc创建独立的"大对象堆段",绕过前端管理。

后端作用如下:

  1. 当前端桶耗尽时,向后端申请新内存;空闲过多时释放堆段。
  2. 碎片整理:合并相邻空闲块(Coalescing),减少外部碎片。
  3. 元数据维护:在每个内存块头部存储大小、状态(占用/空闲)等元数据。

段堆

Windows 段堆(Segment Heap)是 Windows 10 及更高版本引入的新一代堆管理器,旨在替代传统的 NT 堆,为现代应用程序(尤其是 UWP 应用、Microsoft Edge 及关键系统进程)提供更高性能、更低内存开销和更强安全性的内存分配服务。

段堆还有一个特性就是元数据分离,不像NT堆那样将元数据与实际数据混合在一起。

调试实例

txt 复制代码
0:023> dt ntdll!_heap 000001b568940000
   +0x000 Segment          : _HEAP_SEGMENT
   +0x000 Entry            : _HEAP_ENTRY
   +0x010 SegmentSignature : 0xffeeffee
   +0x014 SegmentFlags     : 1
   +0x018 SegmentListEntry : _LIST_ENTRY [ 0x000001b5`68940120 - 0x000001b5`68940120 ]
   +0x028 Heap             : 0x000001b5`68940000 _HEAP
   +0x030 BaseAddress      : 0x000001b5`68940000 Void
   +0x038 NumberOfPages    : 0x10
   +0x040 FirstEntry       : 0x000001b5`68940740 _HEAP_ENTRY
   +0x048 LastValidEntry   : 0x000001b5`68950000 _HEAP_ENTRY
   +0x050 NumberOfUnCommittedPages : 7
   +0x054 NumberOfUnCommittedRanges : 1
   +0x058 SegmentAllocatorBackTraceIndex : 0
   +0x05a Reserved         : 0
   +0x060 UCRSegmentList   : _LIST_ENTRY [ 0x000001b5`68948fe0 - 0x000001b5`68948fe0 ]
   +0x070 Flags            : 2
   +0x074 ForceFlags       : 0
   +0x078 CompatibilityFlags : 0
   +0x07c EncodeFlagMask   : 0x100000
   +0x080 Encoding         : _HEAP_ENTRY
   +0x090 Interceptor      : 0
   +0x094 VirtualMemoryThreshold : 0xff00
   +0x098 Signature        : 0xeeffeeff
   +0x0a0 SegmentReserve   : 0x100000
   +0x0a8 SegmentCommit    : 0x2000
   +0x0b0 DeCommitFreeBlockThreshold : 0x400
   +0x0b8 DeCommitTotalFreeThreshold : 0x1000
   +0x0c0 TotalFreeSize    : 0x256
   +0x0c8 MaximumAllocationSize : 0x00007fff`fffdefff
   +0x0d0 ProcessHeapsListIndex : 0
   +0x0d2 HeaderValidateLength : 0x2c0
   +0x0d8 HeaderValidateCopy : (null) 
   +0x0e0 NextAvailableTagIndex : 0
   +0x0e2 MaximumTagIndex  : 0
   +0x0e8 TagEntries       : (null) 
   +0x0f0 UCRList          : _LIST_ENTRY [ 0x000001b5`68948fd0 - 0x000001b5`68948fd0 ]
   +0x100 AlignRound       : 0x1f
   +0x108 AlignMask        : 0xffffffff`fffffff0
   +0x110 VirtualAllocdBlocks : _LIST_ENTRY [ 0x000001b5`68940110 - 0x000001b5`68940110 ]
   +0x120 SegmentList      : _LIST_ENTRY [ 0x000001b5`68940018 - 0x000001b5`68940018 ]
   +0x130 AllocatorBackTraceIndex : 0
   +0x134 NonDedicatedListLength : 0
   +0x138 BlocksIndex      : 0x000001b5`689402e8 Void
   +0x140 UCRIndex         : (null) 
   +0x148 PseudoTagEntries : (null) 
   +0x150 FreeLists        : _LIST_ENTRY [ 0x000001b5`689407e0 - 0x000001b5`68946af0 ]
   +0x160 LockVariable     : 0x000001b5`689402c0 _HEAP_LOCK
   +0x168 CommitRoutine    : 0x76f7da56`aaec3876     long  +76f7da56aaec3876
   +0x170 StackTraceInitVar : _RTL_RUN_ONCE
   +0x178 CommitLimitData  : _RTLP_HEAP_COMMIT_LIMIT_DATA
   +0x188 UserContext      : 0x000001b5`69113d80 Void
   +0x190 Spare            : 0
   +0x198 FrontEndHeap     : 0x000001b5`68ba0000 Void
   +0x1a0 FrontHeapLockCount : 0
   +0x1a2 FrontEndHeapType : 0x2 ''
   +0x1a3 RequestedFrontEndHeapType : 0x2 ''
   +0x1a8 FrontEndHeapUsageData : 0x000001b5`68941210  -> 0
   +0x1b0 FrontEndHeapMaximumIndex : 0x402
   +0x1b2 FrontEndHeapStatusBitmap : [129]  ""
   +0x233 ReadOnly         : 0y1
   +0x233 InternalFlags    : 0x1 ''
   +0x238 Counters         : _HEAP_COUNTERS
   +0x2b0 TuningParameters : _HEAP_TUNING_PARAMETERS
相关推荐
caimouse1 小时前
Reactos 第 3 章 内存管理 — 【下篇】换出、Section、池
c语言·开发语言·windows·架构
Linlingu1 小时前
OpenClaw对接飞书机器人完整配置教程(长连接模式)
windows·机器人·飞书·办公自动化·数字员工·小龙虾
资源分享助手2 小时前
PeekDesktop:实现类似 macOS Sonoma 点击桌面预览(Windows工具教程)
windows·macos·点击回到桌面
caimouse2 小时前
Reactos 第 3 章 内存管理 — 【上篇】用户态/内核态两侧的内存对象与地址映射
windows·架构
奋斗的小方2 小时前
Java进阶篇1-2:泛型
java·开发语言·windows
caimouse3 小时前
Reactos 第 4 章 对象管理 — 4.6 对象的访问控制 / 4.7 句柄的遗传和继承
开发语言·windows·架构
一杯奶茶¥3 小时前
一键装机助手 一键重装系统工具 专用装机助手(正版)有原版win11、win10、win7最新版系统。
windows
caimouse4 小时前
Reactos 第 4 章 对象管理 — 4.8 系统调用 NtDuplicateObject / 4.9 系统调用 NtClose
开发语言·windows·架构
Qiuner13 小时前
Pico 重塑Agent时代人与数据交互方式
windows·docker·ai·架构