(ntifs.h) RtlCreateHeap 函数

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

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

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

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

HEAP_GENERATE_EXCEPTIONS

指定系统将通过引发异常(例如STATUS_NO_MEMORY)来指示堆失败,而不是返回 NULL

HEAP_GROWABLE

指定堆可增长。 如果 HeapBaseNULL,则必须指定。

HEAP_NO_SERIALIZE

指定当堆函数从此堆分配和释放内存时,不会使用相互排除。 如果未指定HEAP_NO_SERIALIZE,则默认值是序列化对堆的访问。 堆访问的序列化允许两个或多个线程同时分配和释放同一堆中的内存。

[in, optional] HeapBase

指定以下两个操作之一:

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

如果 HeapBaseNULLRtlCreateHeap 将从进程的虚拟地址空间为堆分配系统内存。

[in, optional] ReserveSize

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

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

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

[in, optional] CommitSize

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

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

[in, optional] Lock

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

[in, optional] Parameters

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

typedef struct _RTL_HEAP_PARAMETERS {
    ULONG Length;
    SIZE_T SegmentReserve;
    SIZE_T SegmentCommit;
    SIZE_T DeCommitFreeBlockThreshold;
    SIZE_T DeCommitTotalFreeThreshold;
    SIZE_T MaximumAllocationSize;
    SIZE_T VirtualMemoryThreshold;
    SIZE_T InitialCommit;
    SIZE_T InitialReserve;
    PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;
    SIZE_T Reserved[ 2 ];
} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS;
成员 “值”
时长 RTL_HEAP_PARAMETERS结构的大小(以字节为单位)。
SegmentReserve 段保留大小(以字节为单位)。 如果未指定此值,则使用 1 MB。
SegmentCommit 分段提交大小(以字节为单位)。 如果未指定此值,则使用 PAGE_SIZE * 2。
DeCommitFreeBlockThreshold 取消提交可用块阈值(以字节为单位)。 如果未指定此值,则使用PAGE_SIZE。
DeCommitTotalFreeThreshold 取消提交总可用阈值(以字节为单位)。 如果未指定此值,则使用 65536。
MaximumAllocationSize 可以从堆中分配的最大内存块的大小(以字节为单位)。 如果未指定此值,则使用最高地址和最低地址之间的差值(减少一页)。
VirtualMemoryThreshold 虚拟内存阈值(以字节为单位)。 如果未指定此值,或者如果该值大于最大堆块大小,则使用最大堆块大小0x7F000。
InitialCommit 要为堆提交的初始内存量(以字节为单位)。

必须小于或等于 InitialReserve

如果 HeapBaseCommitRoutine 为非 NULL,则此参数将替代 CommitSize 的值必须是非零值;否则会忽略它。

InitialReserve 要保留堆的初始内存量(以字节为单位)。

如果 HeapBaseCommitRoutine 为非 NULL,则此参数将替代 ReserveSize 的值必须是非零值;否则会忽略它。

CommitRoutine 从堆提交页面的回调例程。 如果此参数为非 NULL,则堆必须是不可增长的。

如果 HeapBaseNULL则 CommitRoutine 也必须为 NULL

Reserved 预留给系统使用。 驱动程序必须将此参数设置为零。
 
typedef NTSTATUS
(NTAPI * PRTL_HEAP_COMMIT_ROUTINE)(
    IN PVOID Base,
    IN OUT PVOID *CommitAddress,
    IN OUT PSIZE_T CommitSize
    );
参数 含义
Base 用于堆的调用方分配内存块的基址。
CommitAddress 指向将接收已提交页面区域的基址的变量的指针。
CommitSize 指向一个变量的指针,该变量将接收页面分配区域的实际大小(以字节为单位)。

返回值

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

注解

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

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

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

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

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

专用堆对象的内存仅可供创建它的进程访问。

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

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

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

  • 进程只有一个线程。
  • 进程有多个线程,但只有一个线程调用特定堆的堆函数。
  • 进程具有多个线程,并且应用程序提供其自己的机制,用于将相互排除到特定堆。
注意  

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

 

要求

   
最低受支持的客户端 此例程在 Microsoft Windows XP 及更高版本上可用。
目标平台 通用
标头 ntifs.h (包括 Ntifs.h)
Library Ntoskrnl.lib
DLL NtosKrnl.exe (内核模式) ;Ntdll.dll (用户模式)
IRQL < DISPATCH_LEVEL

另请参阅

RtlAllocateHeap

RtlDestroyHeap

RtlFreeHeap