如何boost.pool实现再利用分配的内存?(How does boost.pool achiev

2019-08-19 23:59发布

背景

我先前的问题有关boost.pool导致我详细调查boost.pool,现在我有一个补充问题,最后确定我的理解。

序幕

该参考状态以下有关对象池模式:

对象池模式是使用一组初始化的对象保持随时使用,而不是分配和按需摧毁他们的软件造物设计模式。

从我可以告诉, boost.pool (简体)实现了由主要基于一个大小的内存分配和管理手段的对象池模式element_type ,并返回一个简单的指针已分配对象:

element_type * malloc();
void free(element_type * p);

一个简单的例子提升也表明,它没有必要明确free获取的元素:

X * const t = p.malloc();
... // Do something with t; don't take the time to free() it.

据我所知,所分配的内存将被安全释放的池对象的破坏,但如何池知道当客户端获取的内存块已经被释放回池,是可重复使用的,如果它的界面手中夺回一个直接指针到element_type ,还调用free()仍然不需要? 即如何能助推池,如果它不能确定该内存是不是仍然在使用重新使用该内存? 如果它不会重新使用这块内存,这甚至被认为是相同的模式一个由维基参考解释呢?

Answer 1:

如何,如果它不能确定该内存是不是仍然在使用升压池再使用这块内存?

那可不一定。 事实上,它不会重新使用该内存。 它只能保证你不会有任何泄漏时,在销毁池

如果它不会重新使用这块内存,这甚至被认为是相同的模式一个由维基参考解释呢?

该文章您链接说: 对象池可以提供的情况下,一个显著的性能提升,其中初始化类实例的成本高

虽然从升压池介绍: 池一般都使用时有很多分配和小物件释放的。

所以,不,他们是不一样的模式。 一个是指重新使用它们来构建(线程,OpenGL的资源等) 昂贵的对象。 另一种是意在管理大量的小物件,让您有更多的控制比标准分配给。

正如您所指出的,在使用池的方法有两种:

  1. 作为一个分配器,()在适当的时候调用malloc()/免费。 这是基本的池分配器使用,它有助于减少内存碎片
  2. 建设一吨的临时对象,并且也懒得去删除它们。

例如,对于第二种情况:假设有一个图类,其中每个节点使用指针存储其邻居。 现在,你必须让你的图形的深层副本。 您将分配一堆新的节点,从旧到新的复制数据,但现在你必须初始化邻居指针,所以你需要从旧指针指向新的地图:

std::map<node*,node*> old_ptr_to_new_ptr;

这是一个很好的例子池分配器是有用的(我不会去到有关如何使用性病容器池分配器细节):很多小物件(图节点),这将会对被一起删除。



Answer 2:

升压池库提供STL分配器分配相同类型的对象时(而不是,更为高效std::allocator简单的使用newdelete )。 这是斯特劳斯或Alexandrescu的会召唤小对象分配器 。

正如任何自定义allocator类,它的工作原理与本质四个独立的功能:分配,解除分配,构建和破坏。 我认为,他们的名字是不言自明的(除非你感到困惑分配与施工)。 为了从池中获取一个新的对象,首先调用allocate(1)获得一个指针,然后调用construct( ptr, value )对指针ptr得到它构造的副本value (或移动)。 而当你想要删除的对象,你做反向。 这些是所有STL容器下引擎盖使用分配的构建灭,解除分配的对象的机制。

你不应该相信你所提到的维基百科文章(而不是一般要么),这是措辞很差,使用非常含糊和不准确的语言,并采取对对象池模式有点狭隘的观点。 和BTW,引用维基百科是毫无价值的,你不会是谁写的,没有理由去相信它,总是去源。

在维基描述(特别是在源文章)的模式已经从过去的升压池分配器尽力去完成一个非常不同的目标。 正如维基描述,强调的是重用对象,而真正破坏它们(例如,一个线程池是一个很好的例子,因为这将是昂贵的频繁创建和销毁线程,以及源文章感兴趣池数据库服务出于同样的原因提供商)。 在升压池分配器,重点是避免调用堆(的FreeStore)来分配许多小对象,堆不能非常有效地执行,并会导致它变得支离破碎的任务。 这或许应该被称为“小对象分配器”来代替,以避免任何混淆。

如何池知道当客户端获取的内存块已经被释放回池和可重复使用如果接口手中夺回直接指向ELEMENT_TYPE,但一个调用free()还是不需要?

我不认为它可以。 我认为,故事是这样的。 您可以选择只分配了一堆从池中的对象,而没有重新分配他们,这仍然是安全的感觉,当你销毁池分配器,其所有内存被刷新它,包括所有的对象,你留在泳池缠绵。 这就是他们的意思的,简单地说,如果你忘记释放从池中的所有对象的应用程序不会出现内存泄漏超出池分配对象的生命时间“释放的对象不要求”。

但是,如果你不告诉池分配器解除分配,你不再需要的(因此,可重复使用)的对象将不能再使用这些内存插槽,这仅仅是不可能的(考虑到分配器不要”牛逼交付任何一种特殊的智能指针,这将是能够跟踪分配的对象)。

如何,如果它不能确定该内存是不是仍然在使用升压池再使用这块内存?

如果不能确定该内存是不是仍然在使用,那么有没有办法,它可以重复使用的内存。 任何一段代码,会做出这样一个鲁莽的事情,以“假设一个对象不再需要没有被肯定”会是一张毫无价值的代码,因为它显然具有不确定的行为并没有程序员可能可能使用它,直到永远。

如果它不会重新使用这块内存,这甚至被认为是相同的模式一个由维基参考解释呢?

不,它没有实现什么是维基解释。 你必须习惯这样的事实:在术语不幸的方式有时会发生冲突。 这是比较常见的是指什么升压池实现无论是作为一个“内存池”或“小对象分配器”。 这是对于那些相当便宜建设和复制有点小物件优化的结构。 因为堆(的FreeStore)是专为更大的内存块,并倾向于与试图找到小物件的地方,将它用于这个目的处理不好是不是一个好主意,并可能导致堆碎片。 因此,池分配器本质的东西,是在分配相同类型的很多小物件更高效的替代堆。 它不会重新使用的对象,但它可以重复使用已经被释放,就像堆做内存。 它通常分配其存储器(它分配之外)从堆中作为大的连续块(例如,具有std::vector )。 有在适当的时候用小对象分配器等诸多性能优势。 但实际上是从什么是维基描述的非常不同的东西提升池工具。 这是一个什么样池分配器有利于实施者的说明:

使用一个带游泳池的好地方,是在许多(非连续)的小物件可以在堆上分配,或者如果同样大小的物体进行分配和取消重复发生的情况。



文章来源: How does boost.pool achieve re-use of allocated memory?