为啥释放内存后使用的内存量增加了?

Posted

技术标签:

【中文标题】为啥释放内存后使用的内存量增加了?【英文标题】:Why the amount of used memory increases even after the memory is released?为什么释放内存后使用的内存量增加了? 【发布时间】:2013-02-01 09:17:11 【问题描述】:

我发现即使在我的程序中释放内存后,使用的内存量也会增加。所以我写了两个简单的 C++ 测试程序来验证它。

#define NUM 1000000
void Test1()

    PrintMemory("Test1 Beginning");
    double* Data = new double[NUM];

    for(int i = 0; i < NUM; i++)
    
        Data[i] = std::rand() % 1000;
    

    double sum = 0;
    for(int i = 0; i < NUM; i++)
    
        sum += Data[i];
    

    delete [] Data;
    PrintMemory("end");


double* Data[NUM];
void Test2()

    PrintMemory("Test2 Beginning");

    for(int i = 0; i < NUM; i++)
    
        Data[i] = new double;
        *(Data[i]) = std::rand() % 1000;
    

    double sum = 0;
    for(int i = 0; i < NUM; i++)
    
        sum += *(Data[i]);
    

    for(int i = 0; i < NUM; i++)
    
        delete Data[i];
    
    PrintMemory("end");


void main()

    Test1();
    Test2();

在函数PrintMemory中调用APIGetProcessMemoryInfo获取已用内存信息,即结构体PROCESS_MEMORY_COUNTERS_EXPrivateUsage字段。

输出如下:

MemUsed:Test1 开始时为 5544kb MemUsed:最终5568kb MemUsed:Test2 开始时为 5568kb MemUsed: 6404kb 结束

我无法弄清楚输出。我希望在调用delete 之后,使用的内存量应该恢复到以前的值。使用的内存量与 运营商newdelete的电话号码。

【问题讨论】:

为了获得更好的帮助,请以可读的方式格式化您的代码。 @m0skit0 您阅读了整个问题还是只阅读了代码? 【参考方案1】:

对于一百万个 DOUBLE 值,仅负载所需的内存量就是 8 MB。您的打印显示私人使用量并没有增加那么多,那就是内存实际上被正确释放了。

但是,您没有考虑到的是,new 不从裸内存分配,它从堆中获取块,当它们返回时,它们可能仍然 - 在某种程度上 - 归因于等待新分配的进程“缓存”。

这就是您所看到的:一次大的分配/释放内存使用量只增加了一点。有了一百万个小分配,它增加了更多,但仍然比实际有效负载大小要小得多。如果您重复分配,您会发现在某些时候内存不会进一步增加,并且您看到的所有剩余物都只是碎片和堆分配工件。

【讨论】:

谢谢,罗曼。是否有任何文档描述了调用操作符 new 和 delete 时 Windows 会做什么?对于多余的内存,是否可以清理多余的内存? 现在是 Windows 为您执行此操作。 newdelete 由 C++ 运行时实现,内部使用 Windows API。由于分配碎片,清理(从性能指标中排除)所有未使用的内存是不可能的。如果您想“精确到字节”,则需要从头开始实现自己的内存管理器,并覆盖 new/delete 运算符以切换到您自己的实现。 每次分配固定大小的内存。这个简单的测试程序会不会出现内存碎片? 您无法确定,因为您不了解堆管理器操作的内部结构。它是否具有用于微小分配的单独池,是否在释放空闲块时合并空闲块或保留以供将来重用等。与您分配的相比,机器有足够的 RAM,它没有或不需要立即释放不再使用的内存的每个字节。【参考方案2】:

我希望额外的内存实际上与这里使用的堆数量没有直接关系。这可能是一些额外的内存管理开销和类似的,而不是实际的内存分配。正如 Roman 指出的那样,您分配了 8MB,这远远超过了打印输出中相当小的差异。相反,当您分配大量小块时,会使用更多开销来跟踪内存分配,这就是在第二种情况下占用更多内存的原因。当然,该内存不是您分配的直接一部分,因此当实际内存被释放时,它实际上并没有被释放。

我会把它归结为“就是这样”......

我希望如果您每次运行 test1 和 test2 50 次,内存使用量不会在某个时候继续上升 - 它可能不会立即发生,但经过几次运行后,它会达到“稳定状态”。

【讨论】:

以上是关于为啥释放内存后使用的内存量增加了?的主要内容,如果未能解决你的问题,请参考以下文章

C语言free释放内存后为啥指针里的值不变?竟然还可以输出

为啥我们要在 free() 释放内存后清空指针? [复制]

在帧写入循环中使用和不使用自动释放池的内存占用,为啥?

为啥 ARC 在 popViewController 之后不释放内存

为啥我delete后内存没有被释放?

为啥用C#在磁盘上写入文件后内存没有释放