在不终止程序的情况下将动态分配的内存返回给操作系统

Returning dynamically allocated memory back to OS without terminating the program

本文关键字:返回 内存 操作系统 动态分配 终止程序 情况下      更新时间:2023-10-16

我正在编写一个程序,其中我使用了大量但有限的内存。内存是在不同线程的运行时分配和释放的。然而,我注意到程序的内存使用不会保持在指定的范围内。它会随着时间的推移而增加。我编写了下面的示例程序来检查内存是否被释放回操作系统。释放一半已分配的内存以检查内存使用率是否下降。

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

释放它

由于mmapmunmap在某种程度上是昂贵的,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;
}

请注意,mmapMAP_ANONYMOUS在成功时给出了一个归零的内存区域,因此您不需要memset来清除它。

在c++中你也可以定义自己的operator new(调用mmap)和operator delete(如果需要的话,调用munmap)

请参阅Advanced Linux Programming.

进程退出后,该进程使用的所有内存将被回收。操作系统可能会将数据推测性地缓存起来,以防万一(正如这里在Linux Ate My RAM中所解释的那样)。当其他进程需要内存时,该内存将被释放。

编辑:既然你指的是长时间运行的服务器进程,那么你关心的是进程仍在运行时的内存使用情况。我建议将valgrind作为检测应用程序中的内存泄漏的工具,并将RAII作为防止内存泄漏的编码技术。请注意,Linux上的内存使用情况(一般情况下!)很难测量/解释,像ps和top这样的工具的输出可能会误导和不直观,例如根据这个答案。