The heap

The heap is for the more complicated and dynamic memory allocation requirements. A program might allocate on the heap at some point and may release it at some other point, and there need not be a strict boundary between these points, as is the case with stack memory. In the case of stack allocation, you get deterministic allocation and deallocation of values. Also, a value in the heap may live beyond the function where it was allocated and it may later get deallocated by some other function. In that case, the code fails to call free, so it may not get deallocated at all, which is the worst case.

Different languages use the heap memory differently. In dynamic languages such as Python, everything is an object and they are allocated on the heap by default. In C, we allocate memory on the heap using manual malloc calls, while in C++, we allocate using the new keyword. To deallocate memory, we need to call free in C and delete in C++. In C++, to avoid manual delete calls, programmers often use smart pointer types such as unique_ptr or shared_ptr. These smart pointer types have deconstructor methods, which get invoked when they go out of scope internally, calling delete. This paradigm of managing memory is called the RAII principle, and was popularized by C++.

RAII stands for Resource Acquisition Is Initialization; a paradigm suggesting that resources must be acquired during initialization of objects and must be released when they are deallocated or their destructors are called.

Rust also has similar abstractions to how C++ manages heap memory. Here, the only way to allocate memory on the heap is through smart pointer types. Smart pointer types in Rust implement the Drop trait, which specifies how memory used by the value should be deallocated, and are semantically similar to deconstructor methods in C++. Unless someone writes their own custom smart pointer type, you never need to implement Drop on their types. More on the Drop trait in a separate section.

To allocate memory on the heap, languages rely on dedicated memory allocators, which hide all the low-level details like allocating memory on aligned memory, maintaining free chunks of memory to reduce system call overheads, and reducing fragmentation while allocating memory and other optimizations. For compiling programs, the compiler rustc itself uses the jemalloc allocator, whereas the libraries and binaries that are built from Rust use the system allocator. On Linux, it would be the glibc memory allocator APIs. Jemalloc is an efficient allocator library for use in multithreaded environments and it greatly reduces the build time of Rust programs. While jemalloc is used by the compiler, it's not used by any applications that are built with Rust because it increases the size of the binary. So, compiled binaries and libraries always use the system allocators by default.

Rust also has a pluggable allocator design, and can use the system allocator or any user implemented allocator that implements the GlobalAlloc trait from the std::alloc module. This is often implemented by the #[global_allocator] attribute, which can be put on any type to declare it as an allocator.

Note: If you have a use case where you want to use the jemalloc crate for your programs too, you can use the https://crates.io/crates/jemallocator crate.

In Rust, most dynamic types with sizes not known in advance are allocated on the heap. This excludes primitive types. For instance, creating a String internally allocates on the heap:

let s = String::new("foo");

String::new allocates a Vec<u8> on the heap and returns a reference to it. This reference is bound to the variable s, which is allocated on the stack. The string in the heap lives for as long as s is in scope. When s goes out of scope, the Vec<u8> is deallocated from the heap and its drop method is called as part of the Drop implementation. For rare cases where you need to allocate a primitive type on the heap, you can use the Box<T> type, which is a generic smart pointer type.

In the next section, let's look at the pitfalls when using a language such as C that doesn't have all the comforts of automatic memory management.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset