看起来,placement new
在预分配的内存上创建一个新对象,这是否意味着它会花费更少的时间?看起来它比使用旧的普通分配更快new
。那么,如果这样方便快捷,为什么不一直使用placement new
呢?
6 回答
正常(非放置)基本上new
相当于做
T* ptr = static_cast<T*>(malloc(sizeof(T)));
new(ptr) T;
当然,由于错误检查等原因,现实看起来有点不同,但结果或多或少是相同的(通过不相同,您不能delete
以这种方式分配指针,而是需要显式调用析构函数(ptr->~T()
)然后使用 ) 释放内存free
。
所以放置新确实应该比非放置新更快,因为它不需要分配内存。然而问题是内存需要分配到某个地方。所以你基本上用一个调用替换new
了一个调用placement new
和一些用于在某处分配的代码(如果不是,你为什么首先使用new
?)。很明显,这不太方便并且更容易出错。
当然,现在您可以编写一个更快的分配方法,但为此您通常需要进行某种权衡。在不使用更多内存(用于更快识别空闲块的额外数据)或使其非常具体(编写单个对象大小的快速分配比一般对象大小更容易)的情况下,编写一个更快的分配器并不容易。最后,通常不值得付出努力(对于值得付出努力的场景,它可能已经完成,因此您可以使用现有的分配器(它可能在内部使用新的放置))。
当然有用于放置新的用途(有时您确实预先分配了内存),但这根本不是常见的情况
对于大多数程序来说,这是完全没有必要的,因为它们的使用模式并没有必要。对于不使用堆的程序没有任何区别,而且很难正确处理(也就是说,比你的操作系统更好)。您也只能通过优化分配获得这么多。在大多数情况下,任何算法优化都会导致更大的整体加速。自定义分配器可以提供的许多保证(通过预分配内存保证分配的时间限制、低内存碎片)通常是不需要的。
肯定有一些程序可以从自己进行内存管理中受益,但它们很难识别。在你发现内存分配实际上是一个瓶颈之后,就更难找到更好的分配方案了。当所有这些都完成后,通常还是不值得麻烦。
放置 new 的目的之一是使用自定义分配器来创建新对象并调用它们的构造函数。它并不总是更快,因为它仅与您的自定义分配器一样快。
Placement new 用于将对象放置在内存中的特定位置可能需要更少的时间,因为您实际上避免在此步骤分配内存。
但是,它一定是在某个时间点分配的,在此之前可能需要一些时间。如果您确实有理由将对象放置在预分配的内存中,那么使用它是有意义的。
这种new运算符的使用不是单一的。更多细节在这里。
另外,请记住placement new 不会自动调用析构函数!你必须手动foo->~Foo();
为你做。Foo foo;
我发现placement new 将使您的分配明显更快的唯一地方是,如果您有大量相同大小的对象,它们的生命周期有限,导致它们被频繁分配和销毁。如果你不能保证这种行为,你最好使用默认的新实现。
需要大量相同大小对象的应用程序通常可以看到池(或批量)分配的主要加速。基本上,您会为大量该对象分配一个大缓冲区(或页面),然后在请求对象时在其中调用placement new。虽然这可以大大加快速度,但对于大多数程序来说并不是必需的。
尝试为不需要它的程序执行此操作可能只会给您带来最小的加速,但可能会花费您大量的调试时间。
所以真的看你需要什么;如果您要分配大量相同的对象,是的,放置 new 可能会更快。但只有几个对象?我不会打扰。
不过,这并不总是时间问题。例如,您可以使用placement new 来保证堆上的对象对齐。您可以执行以下操作:
void* buffer = aligned_malloc(sizeof(Object), 16);
Object* object = new (buffer) Waypoint();
这对于某些类型是必需的,例如与 SSE 函数和寄存器一起使用的浮点数组。