我已经决定重新发明了一百万次,写下自己的内存池。 我唯一的问题是关于页面大小的界限。
比方说GetSystemInfo()调用告诉我,页面大小是4096字节。 现在,我想预先分配1MB的内存区域(可以更小或更大),并将这个区域分成128个字节块。 我猜,HeapAlloc()/ VirtualAlloc()会有8到16个字节的开销。 可能会更多,我读过的文章谈论60字节。
问题是,我需要注意不要跨页边界有一个128字节的块吗?
我只是在一个块中分配1MB,并将其分成我的块大小?
或者我应该分配4000字节的块(考虑HeapAlloc()开销),并将这4000个字节分成128字节块(4000/128 = 31块,每个128字节),而不是使用剩余字节数(在本例中为4000 – 31×128 = 32字节)?
有一个块越过页面边界不是一个巨大的交易。 这意味着,如果您尝试访问该块并将其完全换出,则会出现两个页面错误,而不是一个。 更重要的是担心块的对齐。
如果您使用小块来保存包含超过1个字节的本机类型的结构,则需要对齐,否则您将面临潜在的糟糕性能,这将超过您可能通过池化获得的任何性能提升。
Windows池功能ExAllocatePool
描述其行为如下:
如果NumberOfBytes是
PAGE_SIZE
或更大,则分配页面对齐的缓冲区。 内存分配PAGE_SIZE
或更少不跨越页面边界。 少于PAGE_SIZE
内存分配不一定是页对齐的,而是对齐到32位系统中的8字节边界和64位系统中的16字节边界。
这可能是一个合理的模式。
我一般认为,当涉及到一个游泳池时,体积越大越好。 理所当然,并根据你将如何使用它。 我一次没有分配1MB的错误(我制作了100MB大小的池)。 您希望将游泳池放在首位是值得的。 也就是说,在相同的连续内存区域中有足够的数据,您可以充分利用缓存局部性。
我发现,如果我使用_align_malloc(),我不需要担心是否将我的子块分散到两个页面将会有所作为。 Freddie回答另一个线程( 如何从C中新的虚拟页面分配内存? )也有帮助。 感谢Harry Johnston,我只是想用它作为内存池对象。