繁体   English   中英

有效地使用多个分配器

[英]Using multiple allocators efficiently

我一直在研究切换我的分配方法,从简化重载新到通过代码库使用多个分配器。 但是,如何有效地使用多个分配器? 我可以通过我的研究设计的唯一方法是让分配器成为全局变量。 虽然,这似乎有问题,因为使用许多全局变量通常是一个“坏主意”。

我想找到如何有效地使用多个分配器。 例如,我可能只有一个分配器用于特定子系统,而另一个分配器用于不同的子系统。 我不确定这样做的唯一方法是使用多个全局分配器,所以我希望有更好的洞察力和设计。

在C ++ 2003中,分配器模型被破坏,并没有真正适当的解决方案。 对于C ++ 2011,分配器模型是固定的,您可以将每个实例分配器传播到包含的对象(当然,除非您选择替换它们)。 通常,为了使它有用,你可能想要使用一个动态多态分配器类型,默认的std::allocator<T>不是必需的(通常我会期望它不是动态多态的,尽管这可能是更好的实施选择)。 但是,[几乎]标准C ++库中进行内存分配的所有类都是将分配器类型作为模板参数的模板(例如,IOStream是一个例外,但通常它们不会分配任何有意义的内存量来保证添加分配器支持)。

在您的一些评论中,您坚持认为分配器实际上需要是全局的:这绝对不正确。 每个分配器识别类型存储给定的分配器的副本(至少,如果它具有任何实例级数据;如果它没有,则没有任何东西要存储,例如使用operator new()的默认分配器的情况和operator delete() )。 这实际上意味着只要存在使用它的任何活动分配器,给予对象的分配机制就需要保持不变。 可以使用全局对象来完成,但也可以使用例如引用计数或将分配器与包含给定它的所有对象的对象相关联来完成。 例如,如果每个“文档”(想想XML,Excel,Pages,无论结构文件)都将分配器传递给其成员,那么分配器可以作为文档的成员存活,并在文档被销毁后销毁所有内容后销毁。 分配器模型的这一部分应该与C ++之前的2011类一起使用,只要它们也使用allocator参数。 但是,在C ++ 2011之前的类中,分配器不会传递给包含的对象。 例如,如果你给一个std::vector<std::string>的分配器,那么C ++ 2011版本将使用给定给std::vector<std::string>的分配器来创建std::string 。适当转换为处理std::string s。 使用pre-C ++ 2011分配器不会发生这种情况。

要在子系统中实际使用分配器,您实际上需要传递它们,或者显式地作为函数和/或类的参数,或者通过作为上下文的分配器感知对象隐式地传递它们。 例如,如果您使用任何标准容器作为传递的上下文的[部分],则可以使用其get_allocator()方法获取已使用的分配器。

您可以使用new展示位置。 这可以用于指定内存区域,也可以用于重载类型的static void* operator new(ARGS) 如果效率很重要且问题很严重,那么全球不是必需的,而且这里真的是个坏主意。 当然,您需要保留一个或多个分配器。

您可以做的最好的事情是了解您的问题,并根据程序中的模式和实际使用情况为您的分配器创建策略。 通用malloc非常擅长它的功能,所以总是将它作为一个基线进行衡量。 如果您不知道您的使用模式,您的分配器可能会比malloc慢。

还要记住,您使用的这些类型将失去与标准容器的兼容性,除非您为标准容器使用全局或线程本地和自定义分配器 - 这在很多情况下很快就会失败。 另一种方法是编写自己的分配器和容器。

多个分配器的一些用途包括减少CPU使用,减少碎片和减少缓存未命中。 因此,解决方案实际上取决于您的分配瓶颈的类型和位置。

通过为活动线程提供无锁堆,消除同步,可以提高CPU使用率。 这可以在具有线程本地存储的内存分配器中完成。

通过从不同堆分配不同生命周期的分配来改进碎片 - 在用户活动任务的单独堆中分配后台IO将确保两者不会相互混淆。 这可能是通过堆积堆栈来实现的,并且当您处于不同的功能范围时推送/弹出。

通过将系统内的分配保持在一起,可以改善缓存未命中。 让Quadtree / Octree分配来自他们自己的堆将保证在视图frustrum查询中存在位置。 最好通过重载特定类(OctreeNode)的operator new和operator delete来完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM