文章摘要
C++标准库在初始化时会预先分配72KB的"紧急池"内存,用于在内存不足时仍能处理异常。这是作者在自定义内存分配器实验中发现的现象,通过覆盖malloc函数并记录分配请求大小观察到。该行为并非普遍现象,而是特定环境下的实现细节。
文章总结
标题:为什么我的C++程序首次内存分配总是72KB?
作者在开发自定义内存分配器时发现一个有趣现象:所有测试程序的首次内存分配请求都是73728字节(72KB)。通过调试工具和gdb回溯分析,发现这一现象源于libstdc++标准库的异常处理机制。
关键发现: 1. 异常处理机制会在程序启动时预先分配"应急内存池",用于在系统内存耗尽时仍能抛出异常 2. 这个72KB的内存池通过malloc分配,其大小由以下因素决定: - 基础对象大小:6个指针大小(64位系统为48字节) - 对象数量:4×指针大小×指针大小(64位系统为64个) - 计算公式:64×(48+16+16)=72KB
技术细节: - 内存池大小可通过环境变量GLIBCXXTUNABLES调整 - 较老版本的Valgrind会将该内存标记为"仍可访问"而非泄漏,新版本已修复 - 应急池在程序退出时通过gnucxx::freeres()函数释放
环境差异说明: - 不同libstdc++版本可能显示71KB等不同大小 - 纯C程序不会出现此分配(仅C++程序链接libstdc++时触发) - 使用libc++等其他标准库实现可能表现不同
这个发现帮助作者理解了自定义内存分配器的测试结果,也揭示了C++异常处理机制的一个底层实现细节。通过深入分析标准库源代码,作者验证了这一现象的技术原理,解决了最初的内存分配疑惑。
(注:原文中关于调试工具实现、gdb操作细节等非核心内容已精简,保留了关键的技术分析和发现过程)
评论总结
评论总结:
- 关于代码公开性
- 用户throwaway2037质疑未公开libmymalloc.so源码:"I would like to see the source code...Nor do I see anything in his GitHub profile"
- 同时指出联系信息缺失:"cannot find his email address anywhere"
- 关于紧急内存池设计
- Joker_vD质疑动态分配的合理性:"Why is this emergency pool not statically allocated?"
- 建议应支持配置:"possible to tune the size of this pool on libc++ startup"
- 关于C++标准适用性
- pjmlp指出这是编译器特性:"This is compiler specific and cannot be generalised as C++"
- aliveintucson质疑术语准确性:"read up on what 'always' means"
- 相关技术类比
- znpy联想到Perl的$^M机制:"Reminds me of Perl's $^M"
- 展示Perl的手动配置示例:"$^M = 'a' x (1 << 16)"
- 技术启发
- jebarker表示获得启发:"good reminder not to be intimidated by assumptions"
- 发现替换malloc比想象简单:"surprisingly simple" to replace malloc for ls