You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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清理时访问无效内存。需确认内存池的逻辑是在对象完全析构后,才将内存块放回池内复用。

修复步骤

  1. 修正ResourcePool的析构调用代码:
template <class Data>
class ResourcePool {
public:
    void recycle(Data* data_ptr) {
        // 执行一些操作
        data_ptr->~Data(); // 修正此处的析构调用
    }
};
  1. 添加重复回收防护逻辑,避免同一对象被多次回收。
  2. 验证多线程环境下的回收流程,确保有正确的同步机制。
  3. 检查内存池的内存管理逻辑,确保对象析构完成后再复用内存。

内容的提问来源于stack exchange,提问作者HCSF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 21:17:53