boost pool 库提供了在分配相同类型的对象时更有效的STL 分配器std::allocator
(而不是简单地使用new
and delete
)。这就是 Stroustrup 或 Alexandrescu 所说的小对象分配器。
与任何自定义分配器类一样,它基本上使用四个独立的函数:分配、解除分配、构造和销毁。我认为它们的名称是不言自明的(除非您对分配与构造感到困惑)。要从池中获取新对象,您首先调用allocate(1)
以获取指针,然后调用construct( ptr, value )
该指针ptr
以将其构造为value
(或移动)的副本。当您想要删除该对象时,您会执行相反的操作。这些是所有 STL 容器在底层使用来分配-构造-销毁-释放其对象的机制。
您不应该相信您提到的维基百科文章(一般也不应该),它的措辞非常糟糕,使用了非常模糊和不准确的语言,并且对对象池模式的看法有些狭隘。顺便说一句,引用维基百科是毫无价值的,你不知道是谁写的,没有理由相信它,总是去源头。
wiki 中描述的模式(尤其是在源文章中)与提升池分配器试图实现的目标有很大不同。如 wiki 中所述,重点是重用对象而不真正销毁它们(例如,线程池是一个很好的例子,因为频繁创建和销毁线程会很昂贵,并且源文章对池化数据库服务感兴趣供应商出于类似原因)。在 boost pool 分配器中,重点是避免调用堆(freestore)来分配许多小对象,堆不能非常有效地执行这项任务并且会导致它变得碎片化。它可能应该被称为“小对象分配器”,以避免任何混淆。
池如何知道客户端获取的内存块何时已释放回池中并且如果其接口交回指向 element_type 的直接指针但仍不需要调用 free() 则可重用?
我不认为它可以。我相信故事是这样发展的。您可以选择只从池中分配一堆对象,而无需释放它们,这仍然是安全的,因为当您销毁池分配器时,它的所有内存都会被它刷新,包括您的所有对象留在池中徘徊。这就是他们所说的“不需要释放对象”的意思,只是如果您忘记从池中释放所有对象,您的应用程序不会在池分配器对象的生命周期之外泄漏内存。
但是,如果您不告诉池分配器释放您不再需要的对象(因此,可以重用),它将无法重用这些内存插槽,这是不可能的(鉴于分配器不' t 提供任何能够跟踪分配对象的特殊智能指针)。
如果无法确定内存是否仍在使用中,提升池如何重新使用该内存?
如果不能确定内存没有被使用,那么它就没有办法重新使用内存。任何会做出如此鲁莽的事情的代码,如“假设不再需要一个对象而不是确定”将是一段毫无价值的代码,因为它显然会具有未定义的行为,并且任何程序员都不可能使用它。
如果它不重用这个内存,这甚至被认为与维基参考解释的模式相同吗?
不,它没有实现 wiki 中解释的内容。您将不得不习惯术语有时会以不幸的方式发生冲突的事实。更常见的是将 boost pool 实现为“内存池”或“小对象分配器”。这是一种针对构造和复制相当便宜的小对象优化的结构。因为堆(freestore)是为更大的内存块量身定做的,并且在尝试为小对象寻找位置时往往表现不佳,因此将其用于该目的并不是一个好主意,并且可能导致堆碎片。因此,池分配器本质上用在分配许多相同类型的小对象时更有效的东西代替了堆。它不重用对象,但它可以重用已释放的内存,就像堆一样。std::vector
)。在适当的时候使用小对象分配器还有许多其他性能优势。但是 boost pool 实现的实际上与 wiki 中描述的有很大不同。以下是实现者对池分配器的优点的描述:
使用 Pool 的好地方是在堆上可能分配许多(不连续的)小对象,或者相同大小的对象的分配和释放重复发生的情况。