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

如何让Sanitizer检测预定义存储中placement new的内存泄漏?

如何让Sanitizer检测预定义存储中内存分配导致的内存泄漏?

在使用Sanitizer做内存泄漏检测时,你会发现bar()里的普通堆分配会被正常检测到泄漏,但foo()中用**定位new(placement new)**在全局预定义存储上构造对象的操作,Sanitizer完全不会报警。这是因为Sanitizer默认只追踪堆内存的分配,而全局/静态预定义存储不属于堆范畴,不会被自动监控。

解决方法:手动标记内存区域的生命周期

要让Sanitizer追踪这类内存,需要使用它提供的非标准内置函数,手动标记内存的分配与释放状态,让Sanitizer把这块区域纳入监控范围。

修改后的示例代码如下:

#include <iostream>
#include <type_traits>

class A
{
};

typename std::aligned_storage<256, alignof(256)>::type store;

A* foo()
{
    // 告知Sanitizer这块内存已被分配
    __sanitizer_allocated_memory(&store, sizeof(store));
    return new (&store) A();
}

// 手动销毁对象并标记内存释放
void cleanup_foo(A* ptr) {
    ptr->~A(); // 显式调用析构函数
    __sanitizer_deallocated_memory(&store, sizeof(store));
}

A* bar()
{
    return new A();
}

int main() {
    A* a = foo();
    cleanup_foo(a); // 先清理旧对象再重新构造
    a = foo();

    A* a2 = bar();
    a2 = bar(); 
}

关键说明

  • 定位new本身不分配内存,只是在已有内存上构造对象,所以Sanitizer默认不会追踪。通过__sanitizer_allocated_memory和__sanitizer_deallocated_memory,我们手动将这块预定义存储模拟成堆内存的生命周期,让Sanitizer可以监控其上的对象状态。
  • 如果重复调用foo()却不销毁前一个对象,Sanitizer就能检测到前一个对象的资源泄漏(如果A类内部有堆分配的成员变量)。
  • 这些内置函数是Sanitizer的扩展,仅在使用-fsanitize=address编译时有效,不属于C++标准。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 00:17:19