EffectiveC++-条款50:了解 new 和 delete 的合理替换时机

本文探讨了为何开发者可能需要替换C++的默认operatornew和operatordelete,包括检测错误、提高性能、统计内存使用、减少额外空间开销、优化内存对齐、集中对象存储和实现特殊行为等七个主要原因。同时指出,在已有内存调试和统计工具的情况下,自定义内存管理不一定总是必要。
摘要由CSDN通过智能技术生成

一. 内容

  1. 怎么会有人想要替换编译器提供的 operator new 或 operator delete 呢?以下是七个常见的理由:

    • 用来检测运用上的错误

      当将 new 所得内存 delete 失败时,会导致内存泄漏。当在 new 所得内存 多次 delete 时,会导致未定义行为。如果自定义 new 或者 delete,就很容易检测出这类错误。此外,各式各样的编程错误,可能导致数据越界,超出已分配的内存,包括上溢(over-runs)和下溢(under-runs)。如果使用自定义的 new,就可以额外分配空间用于放置溢出标签,再使用自定义 delete 检测是否溢出。这样就可以及时检测越界错误。

    • 为了收集使用上的统计数据

      你可能需要了解你的软件是如何使用动态内存,来评估和改善性能。

      常见的内存问题包括:分配区块大小分布如何?寿命分布如何?它们倾向于以 FIFO 次序或 LIFO 次序或随机次序来分配和归还?它们是否随着执行阶段不同存在不同的分配和归还形态?任何时刻所使用的最大动态分配量是多少?

      自定义的 operator new 和 operator delete 使得我们轻易收集到这些信息。

    • 为了增加分配和归还速度

      泛用型分配器往往比定制型分配器慢,特别是当定制型分配器专门针对某特定类型设计时。比如你的程序是单线程,但你的编译器提供的内存分配器具备线程安全,那你或许可以写个不具线程安全的分配器来大幅改善速度。当然,首先请分析你的程序瓶颈确实发生在 new 和 delete 身上。

    • 为了降低缺省内存管理器带来的额外空间开销

      泛用性分配器往往还使用更多的内存,因为它常常在每一个分配区块上使用更多信息。

    • 为了弥补缺省分配器的非最佳齐位

      许多计算机体系结构要求特定的类型必须放在特定的内存地址上。例如它可能要求指针的地址必须是 4 倍数,double 的地址必须是 8 倍数。如果没有这个约束条件,可能导致运行期硬件异常。有些体系必须仁慈,而是宣称如果齐位,便提供较佳效率。

    • 为了将相关对象成簇集中。

      如果你知道某个特定数据对象往往一起使用,而你又希望在处理这些数据时将缺页频率降到最低。那么为此数据对象创建另一个 heap 就有意义。 new 和 delete 的 placement 版本就有可能完成这样的行为,见条款52。

    • 为了获得非传统行为

      有时候你希望 operator new 和 operator delete 做些编译器未做的事情。例如使用 C 的 API,或者 delete 的内存全部赋予 0 值。

  2. 但是也有很多情况下是没必要的,至少不需要自己写:

    • 某些编译器已经具有内存调试(debugging)和 志记(logging)。这很有可能消除自行撰写的需要。许多平台也有商业化的产品,如果有需要可以花点钱买下它们,然后重新链接程序。
    • 开放源码领域的内存管理器。有很多开源的内存管理器项目,比如 Boost 程序库的 Pool 就是这样一个,许多 C++ 书籍也曾展示高效率的小型分配器源码。如果执意要写一个自己版本的 new 和 delete,那么这些开源的项目关于如何保证可移值性,齐位,线程安全,异常安全...细节,都值得借鉴。

二. 总结

  1. 有许多理由需要写个自定的 new 和 delete,包括改善性能,对 heap 运用错误进行调用,收集 heap 使用信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值