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

C++程序栈内存监控疑问:内存未恢复初始值原因解析

栈内存释放与top监控数值不符的原因解析

问题回顾

你编写了如下C++代码:

class BigVector
{
  int foo[500000];
  public:
  void addInformation(int value)
  {
    for (int i(0); i < 500000; ++i)
    {
        foo[i] = value;
    }
  }
};

int compute(int a, int b)
{
    int result = a + b;
    int result1 = 10;
    int result2 = 11;
    int result3 = 12;
    int result4 = 13;
    int result5 = 14;
    int result6 = 15;
    int result7 = 16;
    int result8 = 17;
    int result9 = 18;
    int result10 = 19;
    int result11 = 20;
    int result12 = 21;
    int result13 = 22;
    int result14 = 23;
    int result15 = 24;
    int result16 = 25;
    int result17 = 26;
    int result18 = 27;
    int result19 = 28;
    int result20 = 29;
    {
      int foo[500000];
      for (int i(0); i < 500000; ++i)
      {
        foo[i] = result20;
      }
    }
    BigVector* bigVector = new BigVector;
    bigVector->addInformation(result20);
    delete bigVector;
    return result;
}

int main()
{
    int a = 10;
    int a1 = 43;
    int a2 = 21;
    a = compute(a1, a2);
    return 0;
}

通过g++ -m32 -O0 -g -o program program.c编译后,用gdb断点+top监控得到以下内存数据:

  • 断点1:main调用compute前,1348 KB
  • 断点2:result20 = 29处,1348 KB
  • 断点3:addInformation调用前,3628 KB(已填充嵌套块的foo数组)
  • 断点4:delete bigVector前,5740 KB(已执行addInformation)
  • 断点5:return result处,3800 KB(已执行delete)
  • 断点6:return 0处,3800 KB

你的核心疑问:

  1. compute函数局部变量出作用域后栈内存应释放,但断点6内存与断点1不一致
  2. 断点4内存未回到1348 KB,嵌套块的foo变量应该已释放

核心解答

1. 栈内存的"释放"是进程内部逻辑,不会立即归还操作系统

Linux下进程的栈是一块预先分配的连续虚拟内存区域(32位默认通常为8MB),栈的扩容是通过页错误触发操作系统逐步分配物理内存,但栈的收缩(即局部变量出作用域)只是调整栈指针(ESP/EBP),标记这块空间可被后续栈操作复用,不会主动将物理内存归还给操作系统。

这直接解释了你的两个疑问:

  • 为什么断点4内存没回到1348KB?
    嵌套块的foo[500000]确实在块结束时完成了栈内释放,但之前为它分配的物理内存依然被进程占用。加上new BigVector在堆上分配的约2MB内存(500000个int),总内存是栈已占用的物理内存 + 堆内存,自然不会回到初始的1348KB。

  • 为什么断点6内存与断点1不一致?
    compute函数返回后,栈指针回到调用前的位置,但之前栈扩容时分配的物理内存不会被操作系统回收。top显示的RSS(常驻内存)是进程实际占用的物理内存,这些内存会被保留,直到进程退出,或者操作系统在内存紧张时通过页回收机制收回。

2. delete释放堆内存的细节

delete bigVector确实释放了堆上的BigVector对象内存,但堆内存的释放同样不会立即归还操作系统——堆管理器会把这块内存标记为可复用,后续new操作会优先使用这些已释放的空间,而非向操作系统申请新内存。这也是断点5内存从5740KB降到3800KB,但没回到初始值的原因:栈的物理内存仍被占用。


验证方法

可以用pmap -x <进程PID>查看进程的内存映射,能清晰看到:

  • 栈段的虚拟内存大小已扩容到容纳过大数组的尺寸
  • 栈段的物理内存占用(RSS)和top显示的数值一致
  • 堆段的内存变化对应new/delete操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:17:30