问题
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 munmap
are 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