如果每个对象有一堆初始内存分配,我正在运行很多模拟。模拟必须尽可能快地运行,但分配的速度并不重要。我不关心解除分配。
理想情况下,分配器会将所有内容放在连续的内存块中。 (我认为这有时被称为竞技场?)
我无法使用展平的矢量,因为分配的对象是多态的。
我有什么选择?
答案 0 :(得分:5)
答案 1 :(得分:4)
由于您不关心取消分配,因此可以使用线性分配器。预先分配大量内存并存储指向开头的指针。 malloc(x)将分配指针向前移动x个字节并返回指针的旧值,delete(x)被删除。如上所述,另一张海报已经有an implimentation
分配尽可能紧密地分配,分配速度非常快,并且按照分配的顺序返回内存。完成模拟后,只需重置分配器指向内存开始的指针,并清除分配器外部指向内部对象的任何指针。
如果您希望删除对象,比池快,但不会将数据打包到内存中并且速度不是很快,那么池分配器是一个很好的选择。对那些使用boost:pool。对于游戏来说,这是一个很好的选择,如果你有x个字节来存储说 - 一个级别 - 并且你愿意同时扔掉所有的东西。
顺便说一句,如果您对内存性能感兴趣,请参阅What Every Programmer Should Know About Memory-PDF。它涵盖了诸如引用位置及其对性能的影响之类的内容。具体来说,您可能希望为一起使用的每种类型的对象创建一个池,或者将对象声明为数组结构而不是结构数组
答案 2 :(得分:2)
答案 3 :(得分:1)
通常的技术是固定块分配。请参阅:Lea,Robinson,Knowlton,Grunwald。
编辑:如果频繁分配和解除分配,固定的块分配确实会留下空白。我在一个项目中工作,其中一个类可能分配许多不同大小的子对象但必须保持它们是连续的,我们使用了一个简单的内存池:一次分配所有对象内容所需的所有内存,然后使用placement new来放置他们在里面。
如果您事先不知道对象的内容有多大,您可以编写一个按顺序分配内存的池分配器;即,它保证
Foo *a = new Foo();
Bar *b = new Bar;
b == ((byte *)(a)) + sizeof(Foo);
这将确保在对象的构造函数中发生的所有分配都是连续的。当物体被解除分配时,你会得到大而粗糙的空隙,所以我们不得不经常进行碎片整理;即便如此,净速度增长也是显着的。
答案 4 :(得分:1)
Fixed-Size Block Allocator suite运作良好,并且获得了极具吸引力的许可(麻省理工学院)。
答案 5 :(得分:1)
Dave Hanson的C Interfaces and Implementations包括一个非常好的基于竞技场的分配器。如果内存服务,则没有与对象一起存储元数据,并且它们是从连续的可用空间分配的,因此这是您希望的地方数量。
答案 6 :(得分:0)
这是一个非常重要的主题,只需要wikipedia。
一个具体的例子是在Alexandrescu的书中,应该在他的Loki library中实施。 GCC还附带了std::allocator
的几个实现,只需查看您的发行版。