主要观点:
- ISO C++标准中[basic.start.term]规定了具有静态存储持续时间的构造对象和注册的 std::atexit 函数在 std::exit 调用时被销毁和调用,且 std::exit 调用在销毁和注册函数之前。
- Itanium C++ ABI 采用 __cxa_atexit 进行对象析构注册,原因包括有限的 atexit 保证和动态库卸载处理。
- 一些标准库如 glibc、musl 和 FreeBSD libc 用 __cxa_atexit 实现 atexit。
- 线程存储持续时间的对象在构造时用 __cxa_thread_atexit 注册析构函数。
- 有时不需要退出时的析构函数,如在操作系统内核和内存受限系统中会有不必要的开销和复杂性,还可能导致竞争条件。
- 可以通过使用指向动态分配对象的指针或引用、类模板的空析构函数、编译器优化以及 __clang::no_destroy 属性等方式来禁用退出时的析构函数。
- LLVM 的 ManagedStatic 用于按需构造对象并通过 llvm_shutdown 显式销毁,但其在 DSO 插件使用时可能不适用。
关键信息:
- 不同库中 atexit 与 __cxa_atexit 的实现细节,如 glibc 中 atexit 返回 __cxa_atexit 等。
- 各种方法禁用退出时析构函数的具体代码和原理,如指针引用方式、类模板方式等。
- llvm_shutdown 在 LLVM 中的作用及相关场景。
重要细节:
- 编译器用 __dso_handle 符号注册析构函数,crtbeginS.o 定义.fini_array 节和 __dso_handle 符号。
- dlclose 调用.fini_array 函数,__cxa_finalize 遍历终止函数列表调用匹配的析构函数。
- musl 对 dlclose 和 __cxa_finalize 有 no-op 实现。
- Clang 的 -Wexit-time-destructors 警告及相关补丁和文档。
- 不同编译器对空析构函数优化的情况,如 LLVM 自 2011 年开始优化,GCC 自 2005 年有相关请求。
- llvm_shutdown 在 LLVM 统计机制等中的应用及与 DSO 插件的关系等。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。