为什么将对象地址存储在缓冲区中会在实例化和删除它们时导致内存泄漏?

Why storing objects addresses in a buffer causes a memory leak when instantiating and deleting them?

我正在使用 Visual Studio 2013 开发 Windows 环境。 在我的应用程序中,我需要存储 new-ly 创建的对象的地址。

像这样分配~7.6MB 内存并按预期释放它们的简单操作,程序以~0.4MB 的内存使用量开始:

double* dptr = new double[1000000]; // allocates 8*1000000 ~7.6MB
delete[] dptr;

在最后一行之后,内存使用量又回到了 0.4MB。

但是当我尝试做这样的事情时出现了问题:

// addresses buffer for objects of type 'double'
double** dpptr = new double*[1000000];

// instantiate objects and store their addresses in the buffer
for (int i = 0; i < 1000000; i++)
    dpptr[i] = new double;
/**** Problem 1 ****/

// --- time passes ---

// delete each object
for (int i = 0; i < 1000000; i++)
    delete dpptr[i];

// delete the addresses buffer
delete[] dpptr;
/**** Problem 2 ****/

在我的机器上 sizeof(double*) = 4 和 sizeof(double) = 8,所以如果我计算正确:

但是当我 运行 这个程序时,我遇到了 2 个问题:

  1. 在删除每个对象之前(在实例化它们之后),内存使用量上升到 ~72.9MB 而不是 11.4MB
  2. 在最后一行之后,内存使用量下降到 ~6.1MB 而不是如上所述的 0.4MB。

为什么这会导致超出预期的大量内存使用?

还有程序结束时内存泄漏的原因是什么?

  1. 动态内存分配有开销。对于小分配,开销按比例增加。 8 字节是相当小的单独分配。 (如果使用 malloc 实现)动态内存分配必须与最大的本机对齐方式对齐。那是我系统上的 16 个字节。这将解释 8 字节分配的最小 100% 开销。还会有一些簿记开销来跟踪所有分配。 bookkeping 信息量与分配数量成正比 - 在后一个示例中比前一个示例大得多。我不确定这是否解释了你所有的内存使用,但 11.4MB 肯定是一个不切实际的期望。

  2. 可能没有内存泄漏。更有可能的是,您对进程将内存释放给操作系统的期望只是被误导了。运行时库提供的内存分配通常已实现,因此它通常不会释放内存。这对于小的重新分配和未按 LIFO 顺序完成的重新分配尤其有可能 - 尽管两者是否有影响将取决于实现。

    分配系统为进程保留释放的内存,并将其重新用于未来的分配。要查看是否真的存在泄漏,请重复分配并查看内存使用是否比之前翻倍。