为什么我应该使用新的展示位置?
看起来,placement new
在预先分配的内存上创建了一个新对象,那么这是否意味着它会花费更少的时间?看起来它比使用旧的普通 new
分配更快。那么,如果这样方便快捷,为什么不一直使用 placement new
呢?
As it seems, placement new
creates a new object on a preallocated memory, so does it mean that it would take less time? Looks like it's faster then allocating using the old ordinary new
. Then, if this is so convenient and faster, why not use placement new
all the time?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
正常(非放置)
new
基本上相当于做当然,由于错误检查等原因,现实看起来有点不同,但结果或多或少是相同的(通过不完全相同,您不能
删除
以这种方式分配的指针,而是需要显式调用析构函数(ptr->~T()
),然后释放内存使用免费
)。因此,放置新确实应该比非放置新更快,因为它不需要分配内存。但问题是内存需要分配到某个地方。因此,您基本上已经用对
placement new
的调用和一些用于某处分配的代码替换了对new
的一次调用(如果不是的话,为什么要使用new
> 首先?)。很明显,这不太方便并且更容易出现错误。当然,现在您可以编写更快的分配方法,但为此您通常需要进行某种权衡。如果不使用更多内存(用于更快地识别空闲块的额外数据)或不使其非常具体(编写单个对象大小的快速分配比一般的分配要容易得多),那么编写一个更快的分配器并不容易。最后,这通常不值得付出努力(对于值得付出努力的场景,它可能已经完成,因此您可以使用现有的分配器(可能在内部使用新的放置))。
当然,放置 new 也有用途(有时您确实预先分配了内存),但这并不是常见情况
the normal (nonplacement)
new
is basically equivalent to doingOf course the reality looks a bit different due to errorchecking and such, but the result is more or less the same (through not identical, you can't
delete
a pointer allocated that way, instead you need to call the destructor explicitely (ptr->~T()
) and then release the memory usingfree
).So placement new should indeed be faster then non placement new, since it doesn't need to allocate the memory. However the problem is that the memory needs to be allocated somewhere. So you have essentially replaced one call to
new
with a call toplacement new
and some code for the allocation somewhere (if not why would you usenew
in the first place?). It should be obvious that this is less convinient and more bug prone.Now of course you can write a faster allocation method, but for that you typically need to do some sort of tradeoff. It's not going to be easy to write a allocator which is faster without either using more memory (extra data for faster identification of free blocks) or making it very specific (writing fast allocation of a single objectsize is much easier then a general one). In the end it is typically not worth the effort (for scenarious where it is worth the effort it has likely already been done, so you could use an existing allocator (which likely uses placement new internally)).
There are of course uses for placement new (sometimes you do have the memory preallocated), but that is simply not the common case
对于大多数程序来说这是不必要的,因为它们的使用模式并不需要这样做。对于那些不那么频繁地使用堆的程序来说,这没有什么区别,而且很难做到正确(也就是说,比你的操作系统更好)。而且,通过优化您的分配,您只能获得这么多收益。在大多数情况下,任何算法优化都会带来更大的整体加速。通常不需要定制分配器可以提供的许多保证(通过预分配内存保证分配的时间限制、低内存碎片)。
肯定有一些程序可以从自己进行内存管理中受益,只是很难识别。当您发现内存分配实际上是一个瓶颈之后,就更难找到更好的分配方案了。当所有这些都完成后,通常仍然不值得这么麻烦。
It is simply unnecessary for most programs as their usage patterns don't make it necessary. It makes no difference for programs that don't use the heap as much and it is hard to get right (better than your operating system, that is). Also can you only gain so much by optimizing your allocation. For the most part any algorithmic optimization is going to result in a much larger over-all speed-up. A lot of the guarantees that a customized allocator can offer (guaranteed time limits for allocation through pre-allocated memory, low memory fragmentation) are often not needed.
There are definitely programs that can benefit from doing memory-managment themselves, they are just hard to identify. After you have found that memory-allocation is actually a bottle-neck it is even harder to find a better allocation scheme. When all that is done, it is still not often worth the hassle.
放置 new 的目的之一是使用自定义分配器来创建新对象并调用其构造函数。它并不总是更快,因为它的速度与您的自定义分配器一样快。
One of the purposes of placement new is to use a custom allocator for creating new objects, and calling their constructors. It's not always faster, because it's only as fast as your custom allocator.
用于将对象放置在内存中特定位置的 Placement new 可能会花费更少的时间,因为实际上您在此步骤避免了分配内存。
然而,它必须在某个时刻被分配,这可能需要一些时间。
如果您确实有理由将对象放置在预分配的内存中,那么使用它是有意义的。
这种new运算符并不是一次使用。更多详细信息请参见此处。
另外,请记住,放置 new 不会自动调用析构函数!
您必须手动为
Foo foo;
执行foo->~Foo();
。Placement new used to place an object at a particular location in memory may take less time, because you actually avoid allocating memory at this step.
However, it must have been allocated at some point before which probably takes time.
It makes sense to use it if you actually have a reason to place object at preallocated memory.
It is not a single use of this kind of new operator. More details here.
Also, remember that placement new does not call the destructor automatically!
You have to do
foo->~Foo();
for yourFoo foo;
manually.我发现放置 new 可以使分配速度明显加快的唯一地方是,如果您有大量相同大小的对象,但它们的生命周期有限,导致它们被频繁分配和销毁。如果您不能保证这种类型的行为,那么您最好使用默认的新实现。
The only place that I've found where placement new will make your allocations measurably faster is if you have a large number of the same sized objects that have limited lifetimes, causing them to be allocated and destroyed frequently. If you can't guarantee this type of behavior, you're probably better off using the default new implementation.
需要大量相同大小对象的应用程序通常可以从池(或批量)分配中看到显着的加速。基本上,您会为许多该对象分配一个大缓冲区(或页面),然后在请求该对象时在其中调用placement new。虽然这可以大大加快速度,但对于大多数程序来说并不是必需的。
尝试对并不真正需要它的程序执行此操作可能只会给您带来最小的加速,但可能会花费您大量的调试时间。
所以真正看看你需要什么;如果您要分配大量相同的对象,是的,放置新的可能会更快。但只是一些物体?我不会打扰。
但这并不总是时间问题。例如,您可以使用placement new 来保证对象在堆上的对齐。您可以执行以下操作:
这对于某些类型是必要的,例如与 SSE 函数和寄存器一起使用的浮点数组。
Applications that need a lot of the same size object can often see a major speed-up from pool (or bulk) allocation. Basically you'd allocate a large buffer (or page) for lots of that object, and then calling placement new within it when the object is requested. While this can speed things up a lot, it's not really necessary for most of programs.
Trying to do this for programs that don't really need it would probably only give you a minimal speedup, but could cost you a lot of hours in debugging.
So really look at what you need; if you're allocating a ton of the same object, yes, placement new could be faster. But just a few objects? I wouldn't bother.
It's not always an issue of time, though. For example, you can use placement new to guarantee alignment of your objects on the heap. You can do something like:
This is necessary for some types, such as float arrays to be used with SSE functions and registers.