Heap memory allocation

2019-03-24 17:25发布

问题:

If I allocate memory dynamically in my program using malloc() but I don't free the memory during program runtime, will the dynamically allocated memory be freed after program terminates?

Or if it is not freed, and I execute the same program over and over again, will it allocate the different block of memory every time? If that is the case, how should I free that memory?

Note: one answer I could think of is rebooting the machine on which I am executing the program. But if I am executing the program on a remote machine and rebooting is not an option?

回答1:

Short answer: Once your process terminates, any reasonable operating system is going to free all memory allocated by that process. So no, memory allocations will not accumulate when you re-start your process several times.


Process and memory management are typically a responsibility of the operating system, so whether allocated memory is freed or not after a process terminates is actually dependent on the operating system. Different operating systems can handle memory management differently.

That being said, any reasonable operating system (especially a multi-tasking one) is going to free all of the memory that a process allocated once that process terminates.

I assume the reason behind this is that an operating system has to be able to gracefully handle irregular situations:

  • malicious programs (e.g. those that don't free their memory intentionally, in the hope of affecting the system they run on)
  • abnormal program terminations (i.e. situations where a program ends unexpectedly and therefore might not get a chance to explicitly free its dynamically allocated memory itself)

Any operating system worth its salt has to be able to deal with such situations. It has to isolate other parts of the system (e.g. itself and other running processes) from a faulty process. If it did not, a process' memory leak would propagate to the system. Meaning that the OS would leak memory (which is usually considered a bug).

One way to protect the system from memory leaks is by ensuring that once a process ends, all the memory (and possibly other resources) that it used get freed.



回答2:

Any memory a program allocated should be freed when the program terminates, regardless of whether it's allocated statically or dynamically. The main exception to this is if the process is forked to another process.

If you do not explicitly free any memory you malloc, it will stay allocated until the process is terminated.



回答3:

Even if your OS does cleanup on exit(). The syscall to exit is often wrapped by an exit() function. Here is some pseudo code, derived from studying several libc implementations, to demonstrate what happens around main() that could cause a problem.

//unfortunately gcc has no builtin for stack pointer, so we use assembly
#ifdef __x86_64__
   #define STACK_POINTER "rsp"
#elif defined __i386__
   #define STACK_POINTER "esp"
#elif defined __aarch64__
   #define STACK_POINTER "x13"
#elif defined __arm__
   #define STACK_POINTER "r13"
#else
  #define STACK_POINTER "sp" //most commonly used name on other arches
#endif
char **environ;
void exit(int);
int main(int,char**,char**); 
_Noreturn void _start(void){ 
   register long *sp __asm__( STACK_POINTER ); 
   //if you don't use argc, argv or envp/environ, just remove them
   long argc = *sp;
   char **argv = (char **)(sp + 1);
   environ = (char **)(sp + argc + 1);
   //init routines for threads, dynamic linker, etc... go here
   exit(main((int)argc, argv, environ));
   __builtin_unreachable(); //or for(;;); to shut up compiler warnings
}

Notice that exit is called using the return value of main. On a static build without a dynamic linker or threads, exit() can be a directly inlined syscall(__NR_exit,main(...)); however if your libc uses a wrapper for exit() that does *_fini() routines (most libc implementations do), there is still 1 function to call after main() terminates.

A malicious program could LD_PRELOAD exit() or any of the routines it calls and turn it into a sort of zombie process that would never have its memory freed.

Even if you do free() before exit() the process is still going to consume some memory (basically the size of the executable and to some extent the shared libraries that aren't used by other processes), but some operating systems can re-use the non-malloc()ed memory for subsequent loads of that same program such that you could run for months without noticing the zombies.

FWIW, most libc implementations do have some kind of exit() wrapper with the exception of dietlibc (when built as a static library) and my partial, static-only libc.h that I've only posted on the Puppy Linux Forum.



回答4:

As we say brain of the Operating system is kernel. Operating system has several responsibilities.

Memory Management is a function of kernel.

Kernel has full access to the system's memory and must allow processes to safely access this memory as they require it.

Often the first step in doing this is virtual addressing, usually achieved by paging and/or segmentation. Virtual addressing allows the kernel to make a given physical address appear to be another address, the virtual address. Virtual address spaces may be different for different processes; the memory that one process accesses at a particular (virtual) address may be different memory from what another process accesses at the same address.

This allows every program to behave as if it is the only one (apart from the kernel) running and thus prevents applications from crashing each other


Memory Allocation

malloc

Allocate block of memory from heap

. .NET Equivalent: Not applicable. To call the standard C function, use PInvoke.


The Heap

The heap is a region of your computer's memory that is not managed automatically for you, and is not as tightly managed by the CPU. It is a more free-floating region of memory (and is larger). To allocate memory on the heap, you must use malloc() or calloc(), which are built-in C functions. Once you have allocated memory on the heap, you are responsible for using free() to deallocate that memory once you don't need it any more. If you fail to do this, your program will have what is known as a memory leak. That is, memory on the heap will still be set aside (and won't be available to other processes).


Memory Leak

For Windows

A memory leak occurs when a process allocates memory from the paged or nonpaged pools, but does not free the memory. As a result, these limited pools of memory are depleted over time, causing Windows to slow down. If memory is completely depleted, failures may result.

  • Determining Whether a Leak Exists describes a technique you can use if you are not sure whether there is a memory leak on your system.

  • Finding a Kernel-Mode Memory Leak describes how to find a leak that is caused by a kernel-mode driver or component.

  • Finding a User-Mode Memory Leak describes how to find a leak that is caused by a user-mode driver or application.

Preventing Memory Leaks in Windows Applications

Memory leaks are a class of bugs where the application fails to release memory when no longer needed. Over time, memory leaks affect the performance of both the particular application as well as the operating system. A large leak might result in unacceptable response times due to excessive paging. Eventually the application as well as other parts of the operating system will experience failures.

Windows will free all memory allocated by the application on process termination, so short-running applications will not affect overall system performance significantly. However, leaks in long-running processes like services or even Explorer plug-ins can greatly impact system reliability and might force the user to reboot Windows in order to make the system usable again.

Applications can allocate memory on their behalf by multiple means. Each type of allocation can result in a leak if not freed after use

. Here are some examples of common allocation patterns:

  • Heap memory via the HeapAlloc function or its C/C++ runtime equivalents malloc or new

  • Direct allocations from the operating system via the VirtualAlloc function.

  • Kernel handles created via Kernel32 APIs such as CreateFile, CreateEvent, or CreateThread, hold kernel memory on behalf of the application

  • GDI and USER handles created via User32 and Gdi32 APIs (by default, each process has a quota of 10,000 handles)

For Linux

memprof is a tool for profiling memory usage and finding memory leaks. It can generate a profile how much memory was allocated by each function in your program. Also, it can scan memory and find blocks that you’ve allocated but are no longer referenced anywhere.



回答5:

If I allocate memory dynamically in my program using malloc() but I don't free the memory during program runtime, will the dynamically allocated memory be freed after program terminates?

The operating system will release the memory allocated through malloc to be available to other systems.

This is much more complex than your question makes it sound, as the physical memory used by a process may be written to disk (paged-out). But with both Windows, Unix (Linux, MAC OS X, iOS, android) the system will free the resources it has committed to the process.

Or if it is not freed, and I execute the same program over and over again, will it allocate the different block of memory every time? If that is the case, how should I free that memory?

Each launch of the program, gets a new set of memory. This is taken from the system, and provided as virtual addresses. Modern operating systems use address-space-layout-randomization (ASLR) as a security feature, this means that the heap should provide unique addresses each time your program launches. But as the resources from other runs have been tidied up, there is no need to free that memory.

As you have noted, if there is no way for a subsequent run to track where it has committed resources, how is it expected to be able to free them.

Also note, you can run your program multiple launches that run at the same time. The memory allocated may appear to overlap - each program may see the same address allocated, but that is "virtual memory" - the operating system has set each process up independently so it appears to use the same memory, but the RAM associated with each process would be independent.

Not freeing the memory of a program when it executes will "work" on Windows and Unix, and probably any other reasonable operating system.

Benefits of not freeing memory

The operating system keeps a list of large memory chunks allocated to the process, and also the malloc library keeps tables of small chunks of memory allocated to malloc.

By not freeing the memory, you will save the work accounting for these small lists when the process terminates. This is even recommended in some cases (e.g. MSDN : Service Control Handler suggests SERVICE_CONTROL_SHUTDOWN should be handled by NOT freeing memory)

Disadvantages of not freeing memory

Programs such as valgrind and application verifier check for program correctness by monitoring the memory allocated to a process and reporting on leaks.

When you don't free the memory, these will report a lot of noise, making unintentional leaks difficult to find. This would be important, if you were leaking memory inside a loop, which would limit the size of task your program could deliver.

Several times in my career, I have converted a process to a shared object/dll. These were problematic conversions, because of leaks that were expected to be handled by the OS process termination, started to survive beyond the life of "main".



回答6:

Memory allocated by the malloc needs to be freed by the allocating program.If not and memory is kept on being allocated then one point will come that the program will run out of allowable memory allocation and throw a segmentation or out of memory error. Every set of memory allocation by malloc needs to be accompanied by free.