有没有理由超载全局new和删除?

Mad*_*adH 53 c++ memory-management overloading

除非您正在编程操作系统或嵌入式系统的某些部分,否则有任何理由这样做?我可以想象,对于一些特定的类经常重载内存管理函数或引入一个对象池而创建和销毁的类可能会降低开销,但是在全局范围内做这些事情?

另外
我刚刚在重载的删除功能中发现了一个错误 - 内存并不总是被释放.这是一个不那么重要的内存关键应用程序.此外,禁用这些过载会使性能降低约0.5%.

lea*_*der 76

我们工作的全局new和delete运算符超载了很多原因:

  • 汇集所有小的分配 - 减少开销,减少碎片,可以提高小型重型应用程序的性能
  • 制定分配与已知的生命周期-忽略所有的FreeS直到这一时期的最末端,然后自由所有的人都在一起(当然我们这样做更多具有本地运算符重载不是全局)
  • 对齐调整 - 到高速缓存行边界等
  • alloc fill - 帮助揭示未初始化变量的使用情况
  • 免费填充 - 帮助揭示以前删除的内存的使用情况
  • 延迟自由 - 增加免费填充的效果,偶尔提高性能
  • 哨兵fenceposts - 帮助暴露缓冲区溢出,欠载和偶尔的狂野指针
  • 重定向分配 - 考虑NUMA,特殊内存区域,甚至在内存中保持独立系统分离(例如嵌入式脚本语言或DSL)
  • 垃圾收集或清理 - 对嵌入式脚本语言也很有用
  • 堆验证 - 您可以在N个alloc/frees中遍历堆数据结构,以确保一切正常
  • 会计,包括泄漏跟踪使用快照/统计(堆栈,分配年龄等)

新/删除记帐的想法非常灵活和强大:例如,您可以在发生分配时记录活动线程的整个callstack,并汇总有关该记录的统计信息.如果由于某种原因没有空间将其保留在本地,您可以通过网络发送堆栈信息.您可以在这里收集的信息类型仅受您的想象力(当然还有表现)的限制.

我们使用全局重载,因为在那里挂起许多常见的调试功能很方便,并且根据我们从相同的重载中收集的统计信息,在整个应用程序中进行彻底的改进.

我们仍然会为个别类型使用自定义分配器; 在许多情况下,通过为例如STL数据结构的单个使用点提供自定义分配器可以获得的加速或功能远远超过可以从全局过载中获得的一般加速.

看一下C/C++的一些分配器和调试系统,你会很快想出这些和其他的想法:

(一本古老而又开创性的书是编写固体代码,它讨论了您可能希望在C中提供自定义分配器的许多原因,其中大多数仍然非常相关.)

显然,如果你可以使用任何这些精美的工具,你会想要这样做而不是自己动手.

在某些情况下,它更快,更容易,更少的商业/法律麻烦,没有什么可用于您的平台,或只是更具指导性:挖掘和编写全局超载.


GMa*_*ckG 26

重载new和delete的最常见原因只是检查内存泄漏和内存使用情况统计信息.请注意,"内存泄漏"通常会归结为内存错误.您可以检查双删除和缓冲区溢出等内容.

之后的用途通常是内存分配方案,例如垃圾收集池化.

所有其他情况只是特定的事情,在其他答案中提到(记录到磁盘,内核使用).


Cra*_*rks 15

除了这里提到的其他重要用途,如内存标记,它也是强制应用程序中的所有分配都通过固定块分配的唯一方法,这对性能和碎片有很大的影响.

例如,您可能有一系列具有固定块大小的内存池.覆盖全局new允许您将所有61字节分配定向到具有64字节块的池,所有768-1024字节分配到1024b块池,所有那些高于2048字节块池,以及任何更大的分配一般衣衫褴褛的堆比8kb多.

因为固定块分配器比从堆中无条件地分配更快且更不容易碎片化,这使得你甚至可以强制从池中分配糟糕的3d派对代码,而不是整个地址空间.

这通常在对时间和空间至关重要的系统中完成,例如游戏.280Z28,Meeh和Dan Olson描述了原因.


Sam*_*ell 10

UnrealEngine3将全局new和delete重载为其核心内存管理系统的一部分.有多个分配器提供不同的功能(分析,性能等),并且需要所有分配来完成它.

编辑:对于我自己的代码,我只会做它作为最后的手段.我的意思是,我几乎肯定不会使用它.但我的个人项目显然要小得多,要求也差异很大.


cwa*_*wap 6

一些实时系统会使它们超载,以避免在初始化后使用它们.