Manage Our Application’s Memory Effectively
Learn how to manage our memory effectively.
We'll cover the following
The software depends on memory to run correctly. We won’t necessarily get big performance boosts by using less memory. Still, we’ll be able to scale our application to more users while using fewer servers if we think about how our application uses memory. We can use a few simple techniques to dramatically reduce our exposure to memory problems in Elixir applications.
The main principle covered in this lesson is memory allocation and garbage collection. Elixir doesn’t have a radical garbage collector, but it has critical differences compared to other languages. We’ll cover how garbage collection works before looking at how short-life and long-life processes differ in memory usage. We’ll see two techniques for managing memory:
- Manual garbage collection
- Process hibernation
Let’s dive in.
Elixir’s garbage collector design
Garbage collection is the process of automated memory management in a program’s runtime. This helps prevent our application from taking up a lot of memory by making unused memory available again or returning it to the operating system. The BEAM will keep extra memory rather than replacing it all right away, which helps speed up future allocations. It’s easy to think about garbage collection only as the freeing of memory, but a garbage collector will also allocate memory for our program. There are many different types of garbage collectors, and the BEAM has a somewhat unique one.
We don’t need to know all of the details of how memory allocation and garbage collection works to write practical Elixir applications. Still, we will get better memory utilization in our applications by knowing the basics. Let’s look at a high-level overview of the BEAM garbage collector as of OTP 20, which has been around for a few years. The topic of memory management is very detailed, but this overview won’t go extremely deep.
Each BEAM process has its stack and heap for small data binaries (less than 64 bytes.) Larger binaries are stored in a shared memory space with a reference-counted pointer called ProcBin that lives in a Process’s heap. This means there are many data stacks and heaps in our application, one per process, unlike many other languages with a single stack and heap. A process can be visualized, like so: