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

大量小字符串分配后内存未释放异常问题排查

问题:字符串处理工具内存占用异常排查

我正在开发一款需处理大量字符串的工具,测试时通过top工具发现程序内存占用持续增长,经长时间分析及valgrind等工具排查,排除了自身代码内存泄漏的可能。起初认为是内存碎片导致,但进一步测试后发现无法解释的现象:

测试代码

#include <string>
#include <iostream>
#include <unistd.h>
#include <array>

#define SIZE_LITTLE 100
#define SIZE_BIG 500000

struct Test {
  std::string data;
};

int main(){
  {
    {
      std::string line = "very long string, i tested using a 15Mb string";
      std::array<struct Test*, SIZE_LITTLE> arr;
      for (int i = 0; i < SIZE_LITTLE; i++){
        arr[i] = new Test{line};
      }
      std::cout << "Allocated" << std::endl;
      sleep(5);
      for (int i = 0; i < SIZE_LITTLE; i++){
        delete arr[i];
      }
      std::cout << "Memory released" << std::endl;
      sleep(5);
    }
    std::cout << "Memory released out of scope" << std::endl;
    sleep(5);
  }
  
  {
    {
      std::string line = "smaller string";
      std::array<struct Test*, SIZE_BIG> arr;
      for (int i = 0; i < SIZE_BIG; i++){
        arr[i] = new Test{line};
      }
      std::cout << "Allocated" << std::endl;
      sleep(5);
      for (int i = 0; i < SIZE_BIG; i++){
        delete arr[i];
      }
      std::cout << "Memory released" << std::endl;
      sleep(5);
    }
    std::cout << "Memory released out of scope" << std::endl;
    sleep(5);
  }
}

运行代码后观察到:第一个代码块符合预期,分配后内存占用高,删除指针后内存回到接近0;第二个代码块分配后内存占用高,但删除所有指针及变量出作用域后内存始终不下降。连续运行第二个代码块,预期内存占用会更高,但实际全程保持不变。


原因分析

这是内存分配器的缓存策略导致的,和内存碎片无关,核心细节如下:

  1. 大内存与小内存的分配/释放逻辑差异

    • 第一个代码块中的15MB字符串属于大内存分配,主流内存分配器(如glibc的ptmalloc)会直接通过mmap向操作系统申请内存。当释放这类大内存时,分配器会调用munmap直接将内存还给操作系统,所以top工具能看到内存占用明显下降。
    • 第二个代码块中的"smaller string"属于短字符串,结合std::string的小字符串优化(SSO),Test对象整体是小内存块。分配器对小内存块的处理逻辑不同:释放后不会立刻还给操作系统,而是将其缓存到内部的空闲内存池中,留待后续同规格的内存申请直接复用,避免频繁向系统申请/释放内存的性能开销。
  2. 重复运行内存不变的原因
    第二次运行第二个代码块时,分配器直接从缓存的空闲内存池中取出内存块分配,不需要再向操作系统申请新内存,因此top显示的内存占用不会上升。

  3. top指标的局限性
    top的RES(常驻内存)指标统计的是程序当前占用的物理内存,包括分配器缓存的空闲内存。这些缓存的内存虽然没被程序主动使用,但分配器会保留它们,直到系统内存紧张时才会主动归还给操作系统。如果要查看分配器内部的内存使用细节,可以调用malloc_stats()或malloc_info()函数输出更精准的分配数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 21:35:33