DEV Community

Cover image for JS Memory Management
Ankit parte
Ankit parte

Posted on • Edited on

JS Memory Management

Memory management is a crucial aspect in every kind of coding language which ensures efficient use of memory during code execution.

So understanding how Javascript manages memory can help us write more optimised, performant and scalable application. Memory management issues such as inefficient use of memory and memory leaks can lead to poor application performance, slowdowns and even crashes.

In this article I want to cover about how Javascript handles memory, memory allocation, garbage collection and common memory pitfalls and strategies for efficient memory usage.

1. What is Memory management

Memory management in programming involves controlling how memory is allocated and freed as program runs. Javascript, like many high-level languages, uses automatic memory management through a process called Garbage Collection. This relieves developer from explicitly managing memory but requires an understanding of how memory is allocated and freed to prevent issue like memory leaks and excessive memory consumption.

Memory Life Cycle
  1. Memory Allocation - The process of reserving memory for variables, objects and functions.
  2. Memory Usage - Actively using the allocated memory (e.g., reading or writing to a variable, calling a function).
  3. Memory Release - Once the memory is no longer needed, it should be released back to the system (in JavaScript, this is done by garbage collection).

2. Memory allocation in Javascript

Javascript automatically allocates memory when variables are declared or when objects and when function are created.

For Primitive Values
let x = 1;    // Allocates memory for the number 1
let name = 'Baki';  // Allocates memory for the string 'Baki'
Enter fullscreen mode Exit fullscreen mode

When we declare a primitive, Js allocates memory for the value and stores it directly in the variable. Primitive type data directly stored in the stack and have a fixed size.

For Non-Primitive Values

When we create an object, array or functions they all are stored in heap and the variables contains a reference(or pointer) to the memory location in the heap. These types do not have fixed size and can grow dynamically.

let person = { name: 'Baki', age: 20 };  // Allocates memory for the object in the heap
let numbers = [1, 2, 3, 4];  // Allocates memory for the array in the heap
function Greet() {
  console.log('Hello, World!');
}
//Functions are first class object in Js, which means they are treated as objects and also stored in the heap.
Enter fullscreen mode Exit fullscreen mode

3. Garbage collection

Js automatically frees memory that is no longer in use through a process known as Garbage Collection. The most common algorithm used by Js engines for garbage collection is the Mark and Sweep algorithm.

Mark-and-Sweep Algorithm

It works as follows

  1. Marking Phase - The garbage collectors marks all the variables and objects that are reachable(i.e., accessible from the root, such as global variables, the current function call stack, and event listeners). These are considered alive.

  2. Sweeping Phase - It then checks for variables and objects that are not reachable(i.e., no references to them exist). These objects are considered garbaged and are removed, and memory is released.

//Example
let user = { name: 'Jack' }; // user references an object
user = null;  // user no longer references the object, so the object becomes unreachable and memory is freed
Enter fullscreen mode Exit fullscreen mode

In above example, the object { name : 'Jack' } is no longer referenced when user is set to null. The garbage collector will eventually free up memory for unreachable object.

Root reference

The root of the memory graph is typically the global object(window in browser or global in Node.js). All variables, objects and functions that are reachable from the root are considered 'alive' and will not be garbage-collected.

4. Memory leaks

A memory leak occur when memory that is not longer in use is not released. This can cause your application to consume more and more memory over time, leading to degraded performance and even crashes. Memory leaks are usually caused by unreachable objects that the garbage collector cannot remove because they are still referenced in some part of the code.

Below is the list of common memory leak issues.

1. Unintentional Global Variables

Declaring variables without var, let and const creates implicit global variables, which stays in memory for the lifetime of the page and are not garbage-collected.

function setUser() {
  name = 'Jack';  // Implicit global variable
}
setUser();
// 'name' is now a global variable and will never be garbage-collected

Enter fullscreen mode Exit fullscreen mode
2. Closures

While closures are useful features, But without intention they can cause memory leaks if not managed properly.

function outer() {
  let bigObject = { name: 'Huge object' };
  return function inner() {
    console.log(bigObject);
  };
}

const closure = outer();  // 'bigObject' remains in memory due to closure

// to release memory, assign such variables value to null after use
Enter fullscreen mode Exit fullscreen mode

Here, the inner function creates a closure that holds onto the reference to bigObject. Even though outer() has returned, bigObject cannot be garbage collected as long as the closure exists.

3. DOM References

Sometimes, memory leaks occurs when Js retains references to DOM elements that have been removed from the document. This can prevent the DOM elements from being garbage-collected.

let button = document.getElementById('myButton');
button.addEventListener('click', function handleClick() {
  console.log('Button clicked');
});
// Later, the button is removed from the DOM
document.body.removeChild(button);  // Button still in memory due to event listener

//solution, remove event listeners when they are no longer used
button.removeEventListener('click', handleClick)
Enter fullscreen mode Exit fullscreen mode
4.Timers(setInterval and setTimers)

Timers like setTimer and setInterval can cause memory leaks if not properly cleared.

let counter = 0;
const intervalId = setInterval(() => {
  console.log(counter++);
}, 1000);

// Later, if clearInterval() is not called, this will keep running indefinitely

//solution, always use clearTimer() or clearInterval() when timers no longer needed
Enter fullscreen mode Exit fullscreen mode

Conclusion

Memory management in Js is largely automatic thanks to garbage collection. But understanding how memory allocation and deallocation works is critical for writing efficient and optimised code. As a Good Engineer, your ability to detect and prevent memory leaks, manage closures, handle DOM reference and optimise memory usage in complex applications will have a significant impact on application performance and user experience.

Performance, Efficiency, Maintainability and Scalability matters the most.

Sources of Learning

  • MDN Docs
  • Youtube, Internet
  • LLM, Chatgpt

Top comments (4)

Collapse
 
trplx_gaming profile image
Gabriel Ibe

Wonderful piece!

Are there any more tips you have for writing efficient JS code? I'm eager to know 😁

Also I believe var has been deprecated in the language, that is, as you try to create implicit global variables/being a Python coder, var also hoists variables notwithstanding its scope to the global scope and that's why let and const were introduced to adhere to scoping principles

Overall, var shouldn't be recommended to anyone new to the language

Collapse
 
ankitparte80 profile image
Ankit parte

Thanks pal ✌️, Will definitely going to post something regarding writing efficient Js code sooner.

Collapse
 
laxmann profile image
Laxman Nemane

Thanks, it's Beneficial!