Memory Management Knowledge Every Developer Should Know



Memory management is an important element in programming, but its importance is often overlooked. Programmer Zachary Lee explains the high-level abstraction of memory management as 'an element that every developer should know.'

Memory Management Every Developer Should Know

https://webdeveloper.beehiiv.com/p/memory-management-every-programmer-know



Memory is divided into two areas: the 'stack' and the 'heap'.

·stack
A stack is a data structure with the 'first in, last out' characteristic, which is very suitable for recording function calls in a program. For example, consider the case where there are two functions, 'test()' and 'main()', as shown in the figure below, and test() is called from main().



Your code is executed as an 'entry frame', and each time a function is executed a part of the stack called a frame is allocated that contains context information for that function's general purpose registers and local variables.



When main() calls test(), the process running on the CPU is temporarily suspended and a copy of main()'s general purpose registers is saved on the stack. When test() finishes executing, the registers are restored as if nothing had happened. Thus, each time a function is called, the stack is added, and when the call finishes, the memory occupied by the function frame is freed.

The amount of memory to be allocated for the stack is determined by the compiler when compiling the code. Therefore, data whose size cannot be determined at compile time or whose size can be changed cannot be placed in the stack area.

·heap
When a program needs to dynamically allocate memory, such as for a variable-length array, the data is placed in the heap. Since it is unknown how much memory will be used, a certain amount of space is reserved at the beginning, and if the actual array data exceeds the pre-allocated space, a larger block of memory is reallocated, the existing elements are copied over, and the old memory is freed, dynamically changing the memory size.

In addition to dynamically allocated data, data that needs to be referenced from the entire stack must be allocated in the heap area. Stack memory is freed when the function finishes executing, but it is difficult to determine when to free heap memory, and how it is handled varies depending on the programming language.



In the early days of C, the programmer had to manually manage all memory allocation and release. Although manual management had the advantage of allowing fine-grained control of memory, there was always the risk of oversight, which could slow down the program or even cause it to crash.

Many major programming languages, including Java, use tracing garbage collection, which automatically releases memory by periodically marking and cleaning up objects that are no longer referenced. However, garbage collection is not often used in systems with high real-time requirements, because it causes a Stop The World (STW) event that pauses the program when garbage collection is performed.

Apple's Objective-C and Swift use ARC (Automatic Reference Counting). ARC inserts retain and release statements into each function at compile time to automatically maintain the reference count of objects on the heap. When an object's reference count reaches 0, it can be released. The downside is that it adds a lot of code to handle reference counting, which means it is less efficient and has lower throughput than garbage collection.

Rust uses an ownership mechanism that ties the lifecycle of data on the heap to the lifecycle of stack frames: when a stack frame is destroyed, its heap data is destroyed as well, and the memory it occupies is freed.



In summary, data stored in the stack area is static, has a fixed size and lifecycle, and cannot be referenced from the entire stack, whereas data stored in the heap area is dynamic, has a freely changing size and lifecycle, and can be referenced from various stacks.

in Software, Posted by log1d_ts