我正在使用一个程序,我正在使用大量但有限的内存。 内存在不同的线程上运行时分配和释放。 但是,我注意到程序的内存使用情况不会保持在指定的范围内。 随着时间的推移它会增加。 我写了下面的示例程序来检查内存是否被释放回操作系统。 释放一半分配的内存来检查内存使用是否下降。
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更频繁时,这会引起内存pipe理问题,并且进程数据段变得非常大,导致OS将页面交换到磁盘。 这使得程序和操作系统变得缓慢而没有反应。 有什么办法让操作系统回收释放的内存?
进程退出后,进程使用的所有内存都将被回收。 操作系统可能会保留数据,以防万一(如Linux在这里解释我吃我的RAM )。 当其他进程需要时,内存将被释放。
编辑:因为你的意思是一个长期运行的服务器进程,那么你的担心是内存使用,而进程仍在运行。 我可以建议valgrind作为检测应用程序中内存泄漏的工具, RAII作为防止内存泄漏的编码技术。 小心Linux上的内存使用(通常是!)很难测量/解释,像ps和top这样的工具的输出可能会误导和不直观,比如根据这个答案 。
在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("Freeing\n"); for (i=0; i < 2000 ;i++ ) { if (munmap((void*)p[i], sz)) { perror("munmap"); exit(EXIT_FAILURE); } p[i] = nullptr; }
注意,使用MAP_ANONYMOUS
mmap
正在成功实现一个归零的内存区域,因此您不需要memset
来清除它。
在C ++中,如果需要的话,你也可以定义你自己的operator new
(调用mmap
)和operator delete
(调用munmap
)。
另请阅读高级Linux编程 。