使用placement new分配的对象回收时偶发Core Dump问题排查
问题描述
用户提供的代码如下:
struct SomeStruct2 { // 包含4个基本类型变量 }; struct SomeStruct1 { // 包含10个基本类型变量 std::deque<SomeStruct2> foo; }; template <class Data> class ResourcePool { public: void recycle(Data* data_ptr) { // 执行一些操作 data_ptr->~data_ptr(); } };
应用每日运行约8小时,每隔几天会发生Core Dump,GDB栈回溯信息如下:
(gdb) bt #0 0x00007fa443e32387 in raise () from /lib64/libc.so.6 #1 0x00007fa443e33a78 in abort () from /lib64/libc.so.6 #2 0x00007fa443e74f67 in __libc_message () from /lib64/libc.so.6 #3 0x00007fa443e7d329 in _int_free () from /lib64/libc.so.6 #4 0x0000000000434528 in __gnu_cxx::new_allocator<MyClass::SomeStruct2>::deallocate (this=0x87a410, __p=0x86f260, __t=16) at /opt/rh/devtoolset-10/root/usr/include/c++/10/ext/new_allocator.h:133 #5 0x000000000043147e in deallocate (__n=16, __p=0x86f260, this=0x87a410) at /opt/rh/devtoolset-10/root/usr/include/c++/10/bits/allocator.h:187 #6 std::allocator_traits<std::allocator<MyClass::SomeStruct2> >::deallocate (__a=..., __p=0x86f260, __n=16) at /opt/rh/devtoolset-10/root/usr/include/c++/10/bits/alloc_traits.h:492 #7 0x000000000042e73a in std::_Deque_base<MyClass::SomeStruct2, std::allocator<MyClass::SomeStruct2> >::_M_deallocate_node (this=0x87a410, __p=0x86f260) at /opt/rh/devtoolset-10/root/usr/include/c++/10/bits/stl_deque.h:566 #8 0x000000000042b8ae in std::_Deque_base<MyClass::SomeStruct2, std::allocator<MyClass::SomeStruct2> >::_M_destroy_nodes (this=0x87a410, __nstart=0x86f988, __nfinish=0x86f990) at /opt/rh/devtoolset-10/root/usr/include/c++/10/bits/stl_deque.h:676 #9 0x00000000004263ad in std::_Deque_base<MyClass::SomeStruct2, std::allocator<MyClass::SomeStruct2> >::~_Deque_base (this=0x87a410, __in_chrg=<optimized out>) at /opt/rh/devtoolset-10/root/usr/include/c++/10/bits/stl_deque.h:598 #10 0x000000000042643f in std::deque<MyClass::SomeStruct2, std::allocator<MyClass::SomeStruct2> >::~deque (this=0x87a410, __in_chrg=<optimized out>) at /opt/rh/devtoolset-10/root/usr/include/c++/10/bits/stl_deque.h:1004 #11 0x00000000004270c2 in MyClass::SomeStruct1::~SomeStruct1 (this=0x87a388, __in_chrg=<optimized out>) at my.hpp:67 #12 0x0000000000427109 in ResourcePool<MyClass::SomeStruct1>::recycle (this=0x7ffc3a6f9480, pData=0x87a388) at ResourcePool.hpp:94 #13 0x0000000000422579 in MyClass::try_recycle (this=0x7ffc3a6f9270, data_ptr=0x87a388) at my.hpp:292 #14 0x0000000000421cf9 in MyClass::timer_expired_callback (local_timer_id=8845808, epochExpiration=1679894068466539651, opaqueData=0x7ffc3a6f9270) at my.hpp:453
用户用GDB定位到栈帧11并执行p *this,显示内容未损坏,疑问为:为何使用placement new分配的对象回收时会偶发Core Dump?崩溃发生在释放SomeStruct1内的std::deque时,GDB显示该std::deque无参数。
问题分析与解决方案
核心错误:析构函数调用语法错误
代码中data_ptr->~data_ptr();是完全错误的写法,模板类中调用析构函数的正确方式是data_ptr->~Data();。编译器会将~data_ptr()解析为调用名为~data_ptr的成员函数,而非Data类型的析构函数,这会导致SomeStruct1的析构逻辑未被正确执行,std::deque的内部堆内存未被正确清理,后续触发内存释放时触发_int_free的断言失败,引发Core Dump。其他潜在风险点
- 重复回收问题:如果同一个对象被多次调用
recycle,会导致std::deque被重复析构、内存被重复释放,直接触发内存错误。需要确保每个对象仅被回收一次,比如在对象中添加回收标记,或在ResourcePool内维护已回收对象的集合。 - 线程安全问题:若多线程同时操作同一个ResourcePool或对象,可能破坏std::deque的内部状态,导致析构时出现内存访问错误。需检查回收逻辑是否有正确的锁保护。
- 内存池生命周期问题:如果内存池在对象析构完成前就复用了对应的内存块,会导致std::deque清理时访问无效内存。需确认内存池的逻辑是在对象完全析构后,才将内存块放回池内复用。
- 重复回收问题:如果同一个对象被多次调用
修复步骤
- 修正ResourcePool的析构调用代码:
template <class Data> class ResourcePool { public: void recycle(Data* data_ptr) { // 执行一些操作 data_ptr->~Data(); // 修正此处的析构调用 } };
- 添加重复回收防护逻辑,避免同一对象被多次回收。
- 验证多线程环境下的回收流程,确保有正确的同步机制。
- 检查内存池的内存管理逻辑,确保对象析构完成后再复用内存。
内容的提问来源于stack exchange,提问作者HCSF
相关产品推荐
相关产品推荐

