为什么没有在 top 和 pmap 中释放内存?
Why the memory not freed in top and pmap?
我用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();
}
您正在使用的工具正在监视进程从操作系统分配的内存,它们没有监视 C++ 程序中当前活动的内存分配的大小。
当您使用 C++ 代码分配内存时,它可能不得不向 OS 请求更多。这将增加您监控的值。
但是,当您释放它时,没有要求它将内存返回给OS,因为它可能很快就会再次需要它。
因此,即使您的 C++ 程序释放了内存,C++ 环境 仍会保留它以备您再次需要它。
它是 OS 特定的,但通常一旦进程获取了内存,它就会保留它。您可能没有使用内存,但它可供您的进程使用(在空闲池中)。
缓存,缓存,缓存。哦对了,还有碎片化。
内存是通过不同层分配的。如果您的应用程序分配内存,它将向 C/C++ 运行时请求它。 C/C++ 运行时将检查它自己的数据结构是否有可用内存,如果没有,它会将调用转发给 OS。根据 C/C++ 运行时(和版本),C/C++ 运行时数据结构可能很广泛,或者 C/C++ 运行时可能只是简单地将调用转发给 OS直接。对于 Microsoft Visual Studio(暂时没有使用 Linux,抱歉),我知道:
- 旧版本在 C/C++ 运行时
中具有相当广泛的内存数据结构
- 较新的版本似乎总是将调用转发到 OS(Windows 堆)
这意味着当释放内存时,C/C++ 运行时可能会决定保留内存(出于多种原因,包括如果您决定再次分配内存,能够更快地 return 内存),或者可能 return 它到 OS (如果它已经有很多空闲内存)。 OS 可能会做完全相同的事情:保持内存准备就绪,以防您想要再次分配它,或者立即将其标记为已释放。
哦,是的,碎片化。
内存通常按页划分。在 Intel x86 和 amd64 上,一个页面是 4KB。每个页面都包含一些信息,包括:
- 保护权限(只读、读写、执行(参见 DEP、NoX 位)
- 它的实际位置(物理内存,分页到页面文件,...)
假设您的应用程序分配了 16 乘以 256 字节,并且您很幸运所有这些内存都分配在 4KB 的一页内。如果您现在释放其中的 15 个分配,第 16 个分配将保持分配的内存页,防止 OS 将其标记为已释放。编写一个分配 1.5GB,然后释放 1.4GB,仍然消耗 1.5GB 内存的应用程序非常容易(根据 OS)。
这意味着即使你释放了所有内存,也可能只有一些内部 C/C++ 运行时数据结构,或者一些 3rd 方数据结构(可能是一些缓存)可能会保留一些页面分配,尽管您完美地释放了所有内存。
我用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();
}
您正在使用的工具正在监视进程从操作系统分配的内存,它们没有监视 C++ 程序中当前活动的内存分配的大小。
当您使用 C++ 代码分配内存时,它可能不得不向 OS 请求更多。这将增加您监控的值。
但是,当您释放它时,没有要求它将内存返回给OS,因为它可能很快就会再次需要它。
因此,即使您的 C++ 程序释放了内存,C++ 环境 仍会保留它以备您再次需要它。
它是 OS 特定的,但通常一旦进程获取了内存,它就会保留它。您可能没有使用内存,但它可供您的进程使用(在空闲池中)。
缓存,缓存,缓存。哦对了,还有碎片化。
内存是通过不同层分配的。如果您的应用程序分配内存,它将向 C/C++ 运行时请求它。 C/C++ 运行时将检查它自己的数据结构是否有可用内存,如果没有,它会将调用转发给 OS。根据 C/C++ 运行时(和版本),C/C++ 运行时数据结构可能很广泛,或者 C/C++ 运行时可能只是简单地将调用转发给 OS直接。对于 Microsoft Visual Studio(暂时没有使用 Linux,抱歉),我知道:
- 旧版本在 C/C++ 运行时 中具有相当广泛的内存数据结构
- 较新的版本似乎总是将调用转发到 OS(Windows 堆)
这意味着当释放内存时,C/C++ 运行时可能会决定保留内存(出于多种原因,包括如果您决定再次分配内存,能够更快地 return 内存),或者可能 return 它到 OS (如果它已经有很多空闲内存)。 OS 可能会做完全相同的事情:保持内存准备就绪,以防您想要再次分配它,或者立即将其标记为已释放。
哦,是的,碎片化。 内存通常按页划分。在 Intel x86 和 amd64 上,一个页面是 4KB。每个页面都包含一些信息,包括:
- 保护权限(只读、读写、执行(参见 DEP、NoX 位)
- 它的实际位置(物理内存,分页到页面文件,...)
假设您的应用程序分配了 16 乘以 256 字节,并且您很幸运所有这些内存都分配在 4KB 的一页内。如果您现在释放其中的 15 个分配,第 16 个分配将保持分配的内存页,防止 OS 将其标记为已释放。编写一个分配 1.5GB,然后释放 1.4GB,仍然消耗 1.5GB 内存的应用程序非常容易(根据 OS)。
这意味着即使你释放了所有内存,也可能只有一些内部 C/C++ 运行时数据结构,或者一些 3rd 方数据结构(可能是一些缓存)可能会保留一些页面分配,尽管您完美地释放了所有内存。