4 ms·
The cost of memory management is: 1. The cost of free(), which recursively includes the cost of free()ing all "substructures" (ex: linked list free(head) inclu
by dragontamer 5y ago
The cost of memory management is:
1. The cost of free(), which recursively includes the cost of free()ing all "substructures" (ex: linked list free(head) includes the cost of free()ing the entire linked list)
2. The cost of malloc()
Manual memory management has both malloc() and free(). While garbage-collection memory management removes free() entirely, and does everything with malloc() alone (with "malloc" having some kind of mechanism to automatically detect which bits of RAM are safe to re-allocate without free() to guide it).
These costs can be incredibly complicated to figure out (!!!). free()ing a 4MB linked-list for example, would flush out your L1 cache and L2 cache, as well as take up a significant chunk of your L3 cache.
There is also the issue of fragmentation: malloc() and free() are cheap when the program starts, but as the heap gets more and more confounded by malloc()/free() calls, future calls to malloc() and free() can get slower-and-slower.
So there's a degree of:
* "Housekeeping" -- anti-fragmentation mostly, sorting the free()'d pointers and regions into groups more easily malloc'd() in the future.
* Synchronization -- Having all your threads pull from the same pool of memory is easier to think about, but requires multi-threaded synchronization. For long-lasting free() (ex: freeing a 4MB linked list), this could have one thread slowing down other threads when they try to malloc or free themselves.
-----------
Finally, the application code grossly determines what is faster or slower. Many people assume manual memory management is faster, but consider the following example:
Lets say our application-data consists of 1MB of misc. data + 3999MBs of linked-list data (including the internal pointers). Lets also assume 4000MBs is when the garbage collector runs.
Manual memory management would malloc() the linked list until its of 3999MB size, then the free() call would traverse the entire 3999MB structure every time to find the "deletion" pointers.
In contrast, Garbage collection of malloc() the linked list to 3999MB. The free() doesn't exist, but the linked-list will be detected as "dead data" upon the next malloc() call (only the 1MB of misc. data is traversed).
As such: the garbage-collector will never "Traverse" the entire linked list. The garbage collector only traverses the "live data" whenever it runs (which might be the 1MB of misc. data... but if this misc. data is long lived, then a generational garbage collector won't even traverse that!!).
So really, garbage collectors are best when you have small amounts of live data, and large amounts of malloc() calls. In contrast, manual memory management is best when you have lots of live-data (especially "quickly moving" live data, such that the generational-heuristic doesn't help), and relatively little dead-data.
- titzer 5y agoI've seen internal numbers from $MEGACORP that suggest large-scale C++ applications spend 15-20% of their time doing memory management. Incidentally, the memory fragmentation on those same applications can end up as high as 40%. In GC'd languages fragmentation is typically closer to 10%.
- jeffbee 5y agoThis paper gives 10% for allocation in Google's fleet, and that was before significant efficiency improvements in tcmalloc. https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/44271.pdf https://static.googleusercontent.com/media/research.google.c...
- titzer 5y agoThanks for the link. I am going by ballparks I've heard internally, from less than 3 years ago (so, with newer allocators), and unfortunately can't provide a reference. It would be great if there was more public information from large-scale studies.
- ahh 5y agohttps://research.google/pubs/pub50370/ https://research.google/pubs/pub50370/ gives more up to date information, as does the slide deck here: https://docs.google.com/presentation/d/1taP_gqeRE1XGB2td7f32izso0n2KD6o8QhDDvNDHdVk/edit?usp=sharing https://docs.google.com/presentation/d/1taP_gqeRE1XGB2td7f32... (We get down to 4% on the graph on slide 3.) It's far below 10% now (thanks to the hard work of a lot of people), and Google actually gotten to the point where we chose to spend _more_ time in malloc to make overall efficiency higher.
- ncmncm 5y agoYou can spend literally as much time as you like on memory management. Google has chosen 20%. They have also, by banning exceptions, chosen to spend a very substantial part of their time on checking for error status, and on two-phase initialization and cleanup. I most typically choose 0% post start-up, with 0% fragmentation. For a different problem domain, I might choose differently.