我正在开发一个程序,我正在使用大量但内存有限的程序。在不同的线程上运行时分配和释放内存。但是,我注意到程序的内存使用量不会保持在指定的范围内。它会随着时间的推移而增加。我编写了以下示例程序来检查内存是否正被释放回操作系统。已释放一半已分配的内存以检查内存使用率是否下降。
int main()
{
char *p[COUNT];
for(int i = 0; i < COUNT; i++)
{
p[i] = new char[1048576];
memset (p[i], 0, 1048576);
printf("%p\n", p[i]);
}
printf("done allocating ... \n");
sleep(10);
printf("Freeing\n");
for(int i; i < COUNT; i++)
{
delete[] p[i];
}
while(1)
sleep(1);
}
运行程序后,操作系统似乎无法回收已释放的页面。在分配和释放后,内存使用情况与linux中的“top”命令中看到的相同。它只是将页面标记为可由同一程序重用。 在我的程序中,malloc和free在不同的线程上运行。当malloc被调用的频率高于free并且进程数据段变得非常大,导致OS将页面交换到磁盘时,这会造成内存管理问题。这使得程序和操作系统变得缓慢且无响应。操作系统有什么方法可以回收释放的内存吗?
答案 0 :(得分:2)
在Linux上,您可能会获得virtual memory mmap(2)(malloc
或::operator new
等使用的空间proc(5))。然后您可以使用munmap
由于mmap
和munmap
在某种程度上很昂贵,malloc
(因此::operator new
通常在malloc
之上实现)尝试重复使用free
-d内存区域,所以不要总是将内存释放到内核(低于一个很大的阈值,可能是128K或更高)。
BTW,Advanced Linux Programming为内核提供了一个有用的界面来查询事物。对于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("Freeing\n");
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
)。
另请阅读{{3}}。
答案 1 :(得分:2)
进程退出后,将回收进程使用的所有内存。操作系统可以保持推测性缓存数据,以防万一(如Linux Ate My RAM中所述)。只要另一个进程需要,就会释放内存。
编辑:因为你的意思是一个长时间运行的服务器进程,所以你关心的是内存使用,而进程仍在运行。我可以建议valgrind作为检测应用程序内存泄漏的工具,并RAII作为防止内存泄漏的编码技术。小心Linux(通常!)上的内存使用很难测量/解释,像ps和top这样的工具的输出可能会产生误导和不直观,例如:根据{{3}}。