3

我已经用 valgrind 检查了代码,没有内存泄漏。但我使用'top'查看内存,调用'delete'后它需要295MB内存。
我使用'pmap -x'查看内存,大部分内存成本由[anon]:

Address           Kbytes     RSS   Dirty Mode   Mapping
0000000001114000  301672  301588  301588 rw---    [ anon ]

我不知道为什么内存被释放了,但它仍然需要 295MB。有谁知道为什么?

#include <map>
#include <string>
#include <iostream>
#include <stdio.h>
using namespace std;
void test8() {
  map<string, map<string,string>* > m;
  for (int i = 1; i < 10000; i++) {
    map<string, string>* p = new map<string, string>();
    for (int j = 1; j < 100; j++) {
      (*p)[string(j,'a')] = string(j,'a');
    }
    m[string(i,'a')] = p;
  }

  map<string, map<string,string>* >::iterator it;
  for (it = m.begin(); it != m.end(); it++) {
    it->second->clear();
    delete it->second;
  }
  m.clear();
  cout << "free done" << endl;
}
int main(int argc, char**argv) {
  test8();
  getchar();
}
4

3 回答 3

1

您正在使用的工具正在监视操作系统中进程分配的内存,它们不会监视 C++ 程序中当前活动的内存分配的大小。

当您使用 C++ 代码分配内存时,它很可能不得不向操作系统请求更多。这将增加您正在监视的值。

但是,当您释放它时,不需要将内存返回给操作系统,因为它可能很快就会再次需要它。

因此,即使您的 C++ 程序已释放内存,C++环境也会保留它,以防您再次需要它。

于 2015-09-02T02:54:48.730 回答
1

它是特定于操作系统的,但通常一旦进程获取了内存,它就会保留它。您可能没有使用内存,但它可用于您的进程(在空闲池中)。

于 2015-09-02T02:54:49.883 回答
1

缓存,缓存,缓存。哦,是的,还有碎片化。

内存是通过不同的层分配的。如果您的应用程序分配内存,它将向 C/C++ 运行时请求。C/C++ 运行时将检查它自己的数据结构是否有可用内存,如果没有,它会将调用转发给操作系统。根据 C/C++ 运行时(和版本),C/C++ 运行时数据结构可能很广泛,或者 C/C++ 运行时可能总是直接将调用转发给操作系统。对于 Microsoft Visual Studio(目前不使用 Linux,抱歉),我知道:

  • 旧版本在 C/C++ 运行时中具有相当广泛的内存数据结构
  • 较新的版本似乎总是将调用转发给操作系统(Windows 堆)

这意味着当释放内存时,C/C++ 运行时可能决定保留内存(出于多种原因,包括如果您决定再次分配内存能够更快地返回内存),或者可能会将其返回给操作系统(如果它已经有很多可用内存)。操作系统可能会做同样的事情:保持内存准备好以防您想再次分配它,或者立即将其标记为已解除分配。

哦对了,碎片化。内存通常按页面划分。在 Intel x86 和 amd64 上,一个页面是 4KB。每个页面都包含一些信息,包括:

  • 保护权限(只读、读写、执行(参见 DEP、NoX 位)
  • 它的实际位置(物理内存,分页到页面文件,...)

假设您的应用程序分配了 16 次 256 字节,并且您很幸运,所有这些内存都分配在 4KB 的一页内。如果您现在释放其中的 15 个分配,则第 16 个分配将保持内存页的分配状态,从而防止操作系统将其标记为解除分配。编写一个分配 1.5GB,然后释放 1.4GB 的应用程序非常容易,但仍然消耗 1.5GB 的内存(根据操作系统)。

这意味着即使您释放了所有内存,也可能只有一些内部 C/C++ 运行时数据结构或一些 3rd 方数据结构(可能是一些缓存)可能会保留一些页面,尽管您完全释放了所有内存。

于 2015-09-02T03:24:53.210 回答