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

堆上分配对象删除后内存未释放,求排查思路

问题:uWebSockets内存释放异常

每当有新客户端连接时,会在.message回调内的堆上创建一个新的std::string实例,并将客户端发送的message对象值赋值给它。
我观察到内存(RSS项)随新客户端连接持续增长(例如从约9000字节增长到9004字节、9008字节,每两三个新客户端连接就增长一次),但当客户端正常退出触发.close回调并删除该对象后,内存并未下降。客户端侧通过Qt C++的QWebSocket调用clientSocket.close(),服务端会触发.close回调。

测试时每个客户端发送1024字节数据,我在Debian Linux上使用命令watch -n0.2 'pmap -x process-id | tail -n1'实时监控内存使用情况。
我是该库的新手,肯定哪里操作有误。

用户数据结构与回调代码

PerSocketData定义

struct PerSocketData {
  std::string* someString {nullptr};
};

.message回调

.message = [&](uWS::WebSocket<false, true, PerSocketData> *ws, std::string_view message, uWS::OpCode opCode) {
    PerSocketData* ud = ws->getUserData();
    ud->someString = new std::string(message);
}

.close回调

.close = [](uWS::WebSocket<false, true, PerSocketData> *ws, int /*code*/, std::string_view message) {
     PerSocketData* ud = ws->getUserData();
     ud->someString->clear(); //因delete无效尝试此操作
     ud->someString->shrink_to_fit(); //因delete无效尝试此操作
     delete ud->someString;
     ud->someString = nullptr;
 }

问题分析与解决

  1. RSS未下降的核心原因
    Linux系统的内存分配器(如glibc的ptmalloc)不会在内存释放后立刻将内存归还操作系统,而是会把空闲内存保留在进程的内存池中,供后续分配请求复用。你看到的RSS增长是进程实际占用的物理内存,释放后的内存会被分配器缓存,所以不会立即下降,这是正常的系统行为,并非内存泄漏。

  2. 代码中的内存泄漏隐患
    当前代码存在一个明显问题:如果同一个客户端多次发送消息,.message回调会直接给ud->someString赋值新的堆内存,之前分配的std::string实例会被覆盖,导致这部分内存永远无法释放,形成真正的内存泄漏。

  3. 修正后的代码
    .message回调中先检查并释放已存在的内存,再创建新实例:

.message = [&](uWS::WebSocket<false, true, PerSocketData> *ws, std::string_view message, uWS::OpCode opCode) {
    PerSocketData* ud = ws->getUserData();
    // 先释放已存在的内存,避免泄漏
    if (ud->someString) {
        delete ud->someString;
        ud->someString = nullptr;
    }
    ud->someString = new std::string(message);
}

.close回调无需额外调用clear()和shrink_to_fit(),直接安全释放即可:

.close = [](uWS::WebSocket<false, true, PerSocketData> *ws, int /*code*/, std::string_view message) {
     PerSocketData* ud = ws->getUserData();
     if (ud->someString) {
         delete ud->someString;
         ud->someString = nullptr;
     }
 }
  1. 准确验证内存泄漏
    不要仅依赖RSS判断,使用专业工具检测:比如valgrind --leak-check=full ./your-program,或者gperftools的堆分析器,这些工具能区分内存分配器缓存和真正的内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:07:25