在不终止程序的情况下将动态分配的内存返回给操作系统
Returning dynamically allocated memory back to OS without terminating the program
我正在编写一个程序,其中我使用了大量但有限的内存。内存是在不同线程的运行时分配和释放的。然而,我注意到程序的内存使用不会保持在指定的范围内。它会随着时间的推移而增加。我编写了下面的示例程序来检查内存是否被释放回操作系统。释放一半已分配的内存以检查内存使用率是否下降。
int main()
{
char *p[COUNT];
for(int i = 0; i < COUNT; i++)
{
p[i] = new char[1048576];
memset (p[i], 0, 1048576);
printf("%pn", p[i]);
}
printf("done allocating ... n");
sleep(10);
printf("Freeingn");
for(int i; i < COUNT; i++)
{
delete[] p[i];
}
while(1)
sleep(1);
}
运行程序后,操作系统似乎不会回收释放的页面。在分配和释放之后,内存使用情况与linux中的"top"命令保持相同。它只是将页面标记为可供同一程序重用的自由页面。在我的程序中,malloc和free运行在不同的线程上。当调用malloc的频率比调用free的频率高得多,并且进程数据段变得非常大时,这会导致操作系统将页面交换到磁盘上,从而产生内存管理问题。这使得程序和操作系统,缓慢和无响应。操作系统是否有办法回收释放的内存?
在Linux上,使用mmap(2) (malloc
或::operator new
等使用)可能会获得一些空间(在虚拟内存中)。然后你可以稍后用munmap
由于mmap
和munmap
在某种程度上是昂贵的,malloc
(因此::operator new
通常在malloc
之上实现)尝试重用以前的free
-d内存区域,所以不要总是麻烦地将内存释放给内核(低于一个大阈值,可能是128K或更多)。
顺便说一句,proc(5)为内核提供了一个有用的查询接口。对于pid为1234的进程,可以使用cat /proc/1234/maps
来显示它的地址空间内存映射(从进程内部,使用/proc/self/maps
)
所以你可以写:
const size_t sz = 1048576;
/// allocating loop
for (i=0; i < 2000 ;i++ ) {
void* ad = mmap(NULL, sz, PROT_READ|PROT_WRITE,
MMAP_PRIVATE|MMAP_ANONYMOUS,
-1, (off_t)0);
if (ad == MMAP_FAILED)
{ perror("mmap"); exit (EXIT_FAILURE); }
p[i] = ad;
memset (p[i], 0, sz); // actually uneeded
}
printf ("done allocating ... n");
sleep(5);
// freeing loop
printf("Freeingn");
for (i=0; i < 2000 ;i++ ) {
if (munmap((void*)p[i], sz))
{ perror("munmap"); exit(EXIT_FAILURE); }
p[i] = nullptr;
}
请注意,mmap
和MAP_ANONYMOUS
在成功时给出了一个归零的内存区域,因此您不需要memset
来清除它。
在c++中你也可以定义自己的operator new
(调用mmap
)和operator delete
(如果需要的话,调用munmap
)
请参阅Advanced Linux Programming.
进程退出后,该进程使用的所有内存将被回收。操作系统可能会将数据推测性地缓存起来,以防万一(正如这里在Linux Ate My RAM中所解释的那样)。当其他进程需要内存时,该内存将被释放。
编辑:既然你指的是长时间运行的服务器进程,那么你关心的是进程仍在运行时的内存使用情况。我建议将valgrind作为检测应用程序中的内存泄漏的工具,并将RAII作为防止内存泄漏的编码技术。请注意,Linux上的内存使用情况(一般情况下!)很难测量/解释,像ps和top这样的工具的输出可能会误导和不直观,例如根据这个答案。
- 在 C++ 中访问数组负索引处的内存不会返回垃圾
- 共享内存:MapViewOfFile 返回错误 5
- 将内存分配返回值强制转换为 TYPE 数组
- 在先前调用 string::find 后添加内存分配和内存集会导致它返回 npos.为什么?
- 为什么 free() 函数不将内存返回给操作系统?
- 从函数返回时C++内存管理
- 字符 * 未从重载运算符或内存管理问题正确返回
- 如何返回定义良好的内存部分?例如来自图像数据的像素的颜色值
- 函数,返回变量c++占用的内存位置的大小
- 指针地址的内存偶尔更改了函数前和后返回
- 内存浪费?如果main()应该只返回0或1,那么为什么main是用int而不是短int甚至char声明的
- 返回内存异常错误的矢量
- 数组中的值之和返回内存地址,除非sizeof(array)/2
- 返回内存映射文件后,数据将丢失
- 使用指针数组中的对象调用重载的友元 ostream 插入运算符将返回内存地址
- C++返回内存地址而不是值
- Std::getline()使用cout时返回内存地址
- 在c++程序结束时返回内存
- 删除返回内存问题
- 一旦 cudaMalloc 返回内存不足,每个 cuda API 调用都会返回失败