When you code in JavaScript, in most cases you can do without knowledge of how memory management works. After all, the JavaScript engine does everything for you.
However, sooner or later you will encounter some problems – for example, memory leaks – and you will only be able to get rid of them when you understand exactly how memory allocation works.
In this article, I will tell you about memory management and how the garbage collector works, as well as explain how to avoid the most common types of memory leaks.
Memory Lifecycle
In JavaScript, when we create functions, variables, and so on, the engine allocates memory for them and frees it as soon as the memory is no longer needed.
Memory allocation is the process of “reserving” an area of memory, while freeing it is the return of memory to the system, as a result of which the previously occupied space can be reused.
Each time we declare a variable or create a function, the necessary memory goes through the following steps:
Memory allocation. JavaScript takes over this task: it allocates the memory that will be needed for the object we created.
Memory usage. This is what we explicitly write in the code: reading and writing to memory is nothing more than reading and writing to a variable.
Freeing up memory. This step is also performed by the JavaScript engine: immediately after freeing up the memory, you can use it for other purposes.
In the context of memory management, “objects” include not only JavaScript objects, but also functions with their scopes.
Stack and Heap
Now we know that the JavaScript engine allocates memory for everything that we define in the code, and frees it when this memory is no longer needed. This leads to the question: where is everything stored?
In JavaScript, there are two options for storing data: on the stack and on the heap. Both are names of data structures that are used by the engine for various purposes.
Stack: Static Memory Allocation
A stack is a data structure that is used to store static data, i.e., data whose size is known at compile time. In JavaScript, this includes primitive values (string, number, boolean, undefined, and null) and references to functions and objects.
The engine knows that the size of the data will not change, and therefore allocates a fixed amount of memory for each value.
The process of allocating memory right before execution is called static.
Since the engine allocates a fixed amount of memory for such values, it is logical to assume that there is a limit on the size of primitive values. Depending on the browser used, these limits, as well as the maximum allowed size of the entire stack, may vary.
Heap: Dynamic Memory Allocation
A heap (memory heap) is used to store data such as objects and functions.
Unlike with the stack, the engine does not know how much memory will be needed for certain objects, and therefore allocates memory as needed.
This allocation of memory is called dynamic.
Memory Usage in JavaScript
Using allocated memory in JavaScript usually means reading and writing it.
This can be done by reading or writing the value of a variable or an object property, or even by passing an argument to a function.
Freeing Up Memory That is No Longer Needed
Most problems with memory management occur at this stage.
The most difficult task is figuring out when the allocated memory is no longer needed by the program. This often requires the developer to determine where in the program a certain piece of memory is no longer needed and release it.
High-level languages have a built-in subsystem called the garbage collector. The role of this subsystem is to track memory allocation operations and use it to find out when a piece of allocated memory is no longer needed. If this is the case, the garbage collector can automatically release this fragment.
Unfortunately, this process is not absolutely accurate, since the general problem of finding out whether a certain memory fragment is needed or not is unsolvable (it cannot be solved algorithmically).
Most garbage collectors work by collecting memory that cannot be accessed, that is, one that all variables pointing to are unavailable. This, however, is too bold an assumption about the possibility of freeing memory, since at any time a certain memory area may have variables pointing to it in a certain scope, although this memory area will never be worked on in the program.
Conclusion
So, the article briefly describes the key concepts that form the basis of memory management in JavaScript. We talked about memory management, in particular, we paid special attention to the process of freeing it, the so-called garbage collection. It is at this stage of the memory lifecycle that problems arise, which are expressed in the fact that memory occupied by unnecessary objects cannot be cleared. No matter how well the garbage collection algorithms work in modern implementations of JS engines, the programmer should remember that he also has a certain share of responsibility for the rational use of memory.