RtlCreateHeap 函数 (ntifs.h)

RtlCreateHeap 例程创建可由调用进程使用的堆对象。 此例程在进程的虚拟地址空间中保留空间,并为此块的指定初始部分分配物理存储。

语法

NTSYSAPI PVOID RtlCreateHeap(
  [in]           ULONG                Flags,
  [in, optional] PVOID                HeapBase,
  [in, optional] SIZE_T               ReserveSize,
  [in, optional] SIZE_T               CommitSize,
  [in, optional] PVOID                Lock,
  [in, optional] PRTL_HEAP_PARAMETERS Parameters
);

参数

[in] Flags

指定堆的可选属性的标志。 这些选项通过调用堆函数 (RtlAllocateHeap 和 RtlFreeHeap) 影响对新 的后续访问。

如果未请求可选属性,则调用方应将此参数设置为零。

此参数可使用以下一个或多个值。

含义
HEAP_GENERATE_EXCEPTIONS 指定系统将通过引发异常(如STATUS_NO_MEMORY)来指示堆失败,而不是返回 NULL。
HEAP_GROWABLE 指定堆可增长。 如果 HeapBase 为 NULL,则必须指定 。
HEAP_NO_SERIALIZE 指定当堆函数分配和释放此堆中的内存时,不会使用互斥。 如果未指定HEAP_NO_SERIALIZE,则默认设置是序列化对堆的访问。 堆访问的序列化允许两个或多个线程同时分配和释放同一堆中的内存。

[in, optional] HeapBase

指定以下两个操作之一:

如果 HeapBase 是非 NULL 值,则它指定调用方分配的内存块用于堆的基址。

如果 HeapBase 为 NULL, 则 RtlCreateHeap 将从进程的虚拟地址空间为堆分配系统内存。

[in, optional] ReserveSize

如果 ReserveSize 是非零值,则它指定要为堆保留的初始内存量(以字节为单位)。 RtlCreateHeapReserveSize 向上舍入到下一页边界,然后为堆保留该大小的块。

此参数是可选的,可以为零。 下表总结了 ReserveSizeCommitSize 参数的交互。

结果
ReserveSize 零, CommitSize 最初为堆保留 64 页。 最初提交一页。
ReserveSize 零, CommitSize 非零 RtlCreateHeapReserveSize 设置为等于 CommitSize,然后将 ReserveSize 向上舍入到最接近 (PAGE_SIZE * 16) 的倍数。
ReserveSize 非零, CommitSize 最初为堆提交一页。
ReserveSize 非零, CommitSize 非零 如果 CommitSize 大于 ReserveSize则 RtlCreateHeap 会将 CommitSize 减少到 ReserveSize

[in, optional] CommitSize

如果 CommitSize 是非零值,则它指定要为堆提交的初始内存量(以字节为单位)。 RtlCreateHeapCommitSize 向上舍入到下一页边界,然后在堆的进程虚拟地址空间中提交该大小的块。

此参数是可选的,可以为零。

[in, optional] Lock

指向要用作资源锁的不透明 ERESOURCE 结构的指针。 此参数是可选的,可以为 NULL。 当由调用方提供时,结构必须从非分页池中分配,并通过调用 ExInitializeResourceLiteExReinitializeResourceLite 进行初始化。 如果设置了HEAP_NO_SERIALIZE标志,则此参数必须为 NULL。

[in, optional] Parameters

指向 RTL_HEAP_PARAMETERS 结构的指针,该结构包含创建堆时要应用的参数。 此参数是可选的,可以为 NULL。

返回值

RtlCreateHeap 返回用于访问创建的堆的句柄。

注解

RtlCreateHeap 创建一个专用堆对象,调用进程可以通过调用 RtlAllocateHeap 从中分配内存块。 初始提交大小确定最初为堆分配的页数。 初始保留大小确定最初为堆保留的页数。 保留但未提交的页在进程的虚拟地址空间中创建一个块,堆可以扩展到其中。

如果 RtlAllocateHeap 发出的分配请求超过堆的初始提交大小,系统会为堆提交其他物理存储页,最大大小为堆。 如果堆不可增长,则其最大大小限制为其初始保留大小。

如果堆可增长,则其大小仅受可用内存的限制。 如果 RtlAllocateHeap 的请求超过已提交页面的当前大小,系统会调用 ZwAllocateVirtualMemory 来获取所需的内存,前提是物理存储可用。

此外,如果堆不可增长,则会出现绝对限制:堆中内存块的最大大小为0x7F000字节。 堆的虚拟内存阈值等于最大堆块大小或 Parameters 结构的 VirtualMemoryThreshold 成员的值,以较小者为准。 堆可能还需要填充请求大小以实现元数据和对齐目的,因此,即使 的最大大小足以包含块,在 4096 字节 (1 页) 内分配块的请求也可能失败。 (有关 VirtualMemoryThreshold 的详细信息,请参阅 RtlCreateHeap.)

如果堆可增长,分配大于堆虚拟内存阈值的块的请求不会自动失败;系统调用 ZwAllocateVirtualMemory 来获取此类大型块所需的内存。

专用堆对象的内存只能由创建它的进程访问。

系统使用专用堆中的内存来存储堆支持结构,因此并非所有指定的堆大小都可用于进程。 例如,如果 RtlAllocateHeap 从最大大小为 64K 的堆请求 64 KB (K) ,则请求可能会因系统开销而失败。

如果未 (简单默认) 指定HEAP_NO_SERIALIZE,则堆将在调用过程中序列化访问。 当两个或多个线程尝试从同一堆同时分配或释放块时,序列化可确保相互排斥。 序列化的性能成本很小,但每当多个线程从同一堆分配和释放内存时,必须使用它。

设置HEAP_NO_SERIALIZE可消除堆上的相互排斥。 如果不进行序列化,使用同一堆句柄的两个或多个线程可能会尝试同时分配或释放内存,这可能会导致堆损坏。 因此,只能在以下情况下安全地使用HEAP_NO_SERIALIZE:

  • 进程只有一个线程。

  • 进程有多个线程,但只有一个线程调用特定堆的堆函数。

  • 进程具有多个线程,应用程序为特定堆提供自身的相互排斥机制。

注意

为了防止访问冲突,请使用结构化异常处理来保护写入堆或从堆读取的任何代码。 有关使用内存访问进行结构化异常处理的详细信息,请参阅 处理异常**

要求

要求
最低受支持的客户端 Windows XP
目标平台 通用
标头 ntifs.h (包括 Ntifs.h)
Library Ntoskrnl.lib
DLL NtosKrnl.exe (内核模式) ;Ntdll.dll (用户模式)
IRQL < DISPATCH_LEVEL

另请参阅

RtlAllocateHeap

RtlDestroyHeap

RtlFreeHeap