我决定重新发明轮子百万分之一并编写自己的内存池。我唯一的问题是关于页面大小的界限。
假设GetSystemInfo()调用告诉我页面大小为4096字节。现在,我想预先分配1MB的内存区域(可能更小或更大),并将此区域划分为128字节块。我猜,HeapAlloc()/ VirtualAlloc()的开销在8到16个字节之间。可能会更多,我读过有关60字节的帖子。
问题是,我是否需要注意不要在页面边界上有一个128字节的块?
我只是在一个块中分配1MB并将其分成块大小吗?
或者我应该分配多个块,比如4000个字节(考虑到HeapAlloc()开销),并将这4000个字节细分为128个字节块(4000/128 = 31个块,每个128个字节)和根本不使用剩余的字节(在本例中为4000 - 31x128 = 32字节)?
答案 0 :(得分:1)
跨越页面边界的块不是一个大问题。它只是意味着如果您尝试访问该块并且它已完全换出,您将获得两个页面错误而不是一个。更值得担心的是块的对齐。
如果您正在使用小块来保存包含长度超过1个字节的本机类型的结构,那么您将需要对齐它,否则您将面临潜在的糟糕性能,这将超过您通过池化可能带来的任何性能提升
Windows池功能ExAllocatePool
描述了其行为,如下所示:
如果 NumberOfBytes 为
PAGE_SIZE
或更高,则页面对齐的缓冲区为 分配。PAGE_SIZE
或更少的内存分配不会跨页面 边界。小于PAGE_SIZE
的内存分配不是 必须页面对齐,但与8字节边界对齐 32位系统和64位系统中的16字节边界。
这可能是一个合理的模式。
我通常认为,当涉及到游泳池时,更大更好。当然,在合理的范围内,取决于你将如何使用它。我没有看到一次分配1 MB的任何问题(我已经制作了以100 MB块为单位的池)。您希望首先拥有游泳池是值得的。也就是说,在相同的连续内存区域中有足够的数据可以充分利用缓存局部性。
答案 1 :(得分:0)
我发现如果我使用了_align_malloc(),我就不用担心将我的子块扩展到两个页面会有所不同。 Freddie对另一个线程(How to Allocate memory from a new virtual page in C?)的回答也有所帮助。谢谢Harry Johnston,我只想将它用作内存池对象。