我一直在研究如何将我的分配方法从简单重载新的方式转换为通过代码库使用多个分配器。但是,我如何有效地使用多个分配器呢?通过我的研究,我能想到的唯一办法是让这些分配器成为全局变量。然而,由于通常有很多全局变量的使用是一个“坏主意”,所以这似乎存在问题。
我希望找到如何有效使用多个分配器的方法。例如,我可能需要一个分配器只用于特定子系统,另一个分配器则用于不同的子系统。我不确定是否唯一的方法是使用多个全局分配器,因此我希望能获得更好的见解和设计。
我一直在研究如何将我的分配方法从简单重载新的方式转换为通过代码库使用多个分配器。但是,我如何有效地使用多个分配器呢?通过我的研究,我能想到的唯一办法是让这些分配器成为全局变量。然而,由于通常有很多全局变量的使用是一个“坏主意”,所以这似乎存在问题。
我希望找到如何有效使用多个分配器的方法。例如,我可能需要一个分配器只用于特定子系统,另一个分配器则用于不同的子系统。我不确定是否唯一的方法是使用多个全局分配器,因此我希望能获得更好的见解和设计。
C++2003版本的分配器模型存在问题,没有真正的解决方案。对于C++2011版本,修复了分配器模型,并且您可以拥有每个实例自己的分配器,这些分配器会传播到包含的对象中(除非当然您选择替换它们)。通常情况下,为了使此功能更加有用,您可能需要使用动态多态分配器类型,而默认的std::allocator<T>
不要求是(通常我预计它不是动态多态的,尽管这可能是更好的实现选择)。但是,标准C++库中几乎所有进行内存分配的类都是以分配器类型作为模板参数的模板类(例如IOStreams是一个例外,但通常它们不会分配任何有趣数量的内存来支持添加分配器支持)。
operator new()
和operator delete()
的默认分配器的情况)。这实际上意味着分配给对象的分配机制需要保持不变,只要有任何活动的分配器使用它。这可以使用全局对象来完成,但也可以使用例如引用计数或将分配器与包含其所有给定对象的对象相关联来完成。例如,如果每个“文档”(考虑XML、Excel、Pages等结构文件)将分配器传递给其成员,分配器可以作为文档的成员存在,并在文档销毁后销毁,以及其所有内容被销毁。分配器模型的这一部分应与先前的C++2011类一起工作,只要它们带有一个分配器参数。然而,在先前的C++2011类中,分配器不会传递给包含的对象。例如,如果您向std::vector<std::string>
提供分配器,则C ++ 2011版本将使用适当转换处理std::string
来创建std::string
。这在先前的C++2011分配器中不会发生。get_allocator()
方法获取所使用的分配器。std::shared_ptr<my_allocation_base>
作为分配器 my_allocator
的成员。实际的分配逻辑将位于从 my_allocation_base
派生的类中。如果您只有一种分配方法,当然可以直接将逻辑放入指向的对象中。使用 weak_reference
(不知道这是什么)听起来好像行不通:您希望每个仍然持有相应分配内存的对象都有一个对分配对象的实际引用,并且在释放后减少引用计数。 - Dietmar Kühlnew
放置。这既可以用于指定内存区域,也可以用于重载类型的static void* operator new(ARGS)
。全局变量在这里不是必需的,而且如果效率很重要并且您的问题很苛刻,那么这真的是一个坏主意。当然,您需要保留一个或多个分配器。malloc
非常擅长它所做的事情,因此始终将其用作一条基线来进行测量。如果您不知道自己的使用模式,则您的分配器可能会比malloc
慢。this->view()->rootView()->bitmapImageAllocator()
。在这种情况下,分配器由根视图持有。您还可以隐藏我提到的默认 operator new
,以强制执行特定的分配器,或将其作为构造函数参数传递。虽然不总是方便,但在需要自定义分配器的情况下,可以传递/保留这些引用。因此,对象可以保留对引用的控制,或者根据需要将它们作为参数传递。您还可以使它们成为线程本地的。 - justin多个分配器的一些用途包括减少CPU使用率、减少碎片化和减少缓存未命中。因此,解决方案实际上取决于您的分配瓶颈类型和位置。
通过为活动线程提供无锁堆来消除同步,可以改善CPU使用情况。这可以在内存分配器中使用线程本地存储来完成。
通过将具有不同生命周期的分配从不同的堆中分配来改善碎片化——将后台IO分配到与用户活动任务不同的堆中将确保两者不会相互干扰。这通常是通过为堆设置堆栈,在不同的功能作用域中进行推入/弹出来完成的。
通过将分配保持在系统内部来改善缓存未命中。将Quadtree/Octree分配来自它们自己的堆将确保视图 frustrum 查询中存在局部性。最好通过重载特定类(OctreeNode)的operator new和operator delete来完成。