Returning dynamically allocated memory back to OS without terminating the program

跟風遠走 提交于 2019-12-20 02:06:19

问题


I am working on a program where I am using large but limited amount of memory. Memory is allocated and freed on run time on different threads. However, I noticed that the memory usage of the program would not remain within specified bounds. It would increase as time passed on. I wrote the following sample program to check whether memory is being freed back to the OS. Half the allocated memory was freed to check if the memory usage went down.

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);
}

After running the program, it seemed that the OS would not reclaim the freed pages. The memory usage remains the same as seen in "top" command in linux, after allocating and after freeing. It simply marks the pages as free for reuse by the same program. In my program, malloc and free are running on different threads. This poses memory management problem when malloc is called a lot more frequently than free and the process data segment grows very large, causing OS to swap pages to disk. This makes the program and OS, slow and unresponsive. Is there any way for the OS to reclaim freed memory ?


回答1:


After the process has exited, all memory used by the process will be reclaimed. The OS may keep the data speculatively cached just in case (as explained here on Linux Ate My RAM). The memory will be freed up whenever another process needs it.

EDIT : since you mean a long-running server process, then your concern is memory usage while the process is still running. May I suggest valgrind as a tool to detect memory leaks in your application, and RAII as a coding technique to prevent memory leaks. Careful that memory usage on Linux (and in general!) is difficult to measure / interpret, the output of tools like ps and top can be misleading and unintuitive e.g. as per this answer.




回答2:


On Linux, you might get some space (in virtual memory) with mmap(2) (which is used by malloc or ::operator new, etc...). Then you can release later it with munmap

Since mmap and munmapare somehow expensive, malloc (hence ::operator new which is often implemented above malloc) try to reuse previously free-d memory zones, so don't bother to always release memory to the kernel (below a big threshold, perhaps 128K or more).

BTW, proc(5) provides a useful interface to the kernel to query things. For a process of pid 1234, you could cat /proc/1234/maps to show its address space memory map (from inside your process, use /proc/self/maps)

So you could code:

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;
}

Notice that mmap with MAP_ANONYMOUS is giving on success a zeroed memory zone, so you don't need the memset to clear it.

In C++ you might also define your own operator new (calling mmap) and operator delete (calling munmap) if so wanted.

Read also Advanced Linux Programming.



来源:https://stackoverflow.com/questions/22323037/returning-dynamically-allocated-memory-back-to-os-without-terminating-the-progra

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!