Exploring Object and Memory Management Techniques in JavaScript
How JavaScript Manages Object Memory
Let us understand what Objects really are.
In real life, everything when we look around is an object such as book, car, pen, mobile, TV and the list goes on. Objects contain characteristics which can be different from each other.
An object mainly has properties and methods associated with it. Here is an example of a car to better understand the statement.
As you can see here a car contains some properties such as price, weight, name etc which describes something about the car, whereas a car has few methods like start(), stop(), brake() and it could be many more which describes what functions a car can perform.
I hope the basic idea of what an object is clear🙂
Now let us come back to Javascript and try to undertand what an how an object is ?🤔
An object is a data structure which stores key-value pairs which could either be its properties or methods. Let’s try to depict the above car in the form of a Javascript object.
const car = {
name : 'Mercedes',
color : 'Silver',
weight : '2070KG',
price : 128600,
start : function(){
console.log('Engine started....')
}
drive : function(){
console.log('Driving....')
}
brake : function(){
console.log('Brakes applied....')
}
music : function(){
console.log('Music is playing....')
}
}
This is how a car is represented in the form of an object in Javascript. That’s great but how will I access the properties and methods of this car object ?🤔
In order to access the properties or methods, you just need to access its keys🙂
console.log(car.color) // Silver
console.log(car.name) // Mercedes
console.log(car.price) // 128600
console.log(car.start()) // Engine started
console.log(car.music()) // Music is playing
Memory
Memory is the space where the program is executed. It contains two components Stack and Heap memory. Let us understand them one by one.
Stack - Stack memory is a reserved area of memory in a computer system that stores data in a last-in, first-out (LIFO) manner. This means that the most recently added item to the stack is the first item to be removed. It stores primitive values such as string, number, boolean, null, undefined, symbol and BigInt.
Heap - Heap memory is a region of a computer's memory that is used for dynamic memory allocation. It stores non-primitive types such as objects, arrays, functions etc.
When we create any variable in our program it is allocated the stack memory, while the objects are allocated the heap memory and its memory address is held in the stack. Look at the diagram bellow to understand it more clearly.
As you can see above, the variable names such as name and age are held directly into the stack, while the object person is held in the heap and its memory address is stored in the stack.
Now look at the code bellow and tell me what is the value of a ?⬇️
let a = 10;
let b = a;
b = 20;
console.log(a)
We declared a variable ‘a‘ whose value is 10. Then we made a copy of that and assigned it to variable ‘b‘. b stores the copy of ‘a‘ and not the actual value. So, if you try to change the value b to 20, the change will only be reflected inside the copy and not in the actual variable a. So, the value of ‘a‘ remains unchanged and will print the same 10.
Now look at the code below and tell me what is the value of obj1.name ?
let obj1 = {name:"Vansh"};
let obj2 = obj1;
obj2.name = "Aniket";
console.log(obj1.name);
Now, since object are created inside the heap memory and its address is stored inside the stack. So whenever we try to assign a new value to a key, the changes are reflected in both the objects because both the objects obj1 and obj2 are pointing to the same memory location, and hence any change in obj2.name will also be seen in obj1.name. Therefore obj1.name will also print “Aniket“.
Shallow Copy v/s Deep Copy
Shallow copy - Shallow copy only copies the refrences and not the actual values. It can be performed by using the spread operator(…). Example →
let obj1 = {name : "Vansh", address : {city : "Ranchi", state : "Jharkhand"}}; let obj2 = {...obj1}; obj2.name = "Aniket" obj2.address.city = "Jamshedpur" console.log(obj2.address.city) // Jamshedpur, nested reference is shared
Deep copy - Creates a complete new copy of an object. For that first we need to convert the object into string and again convert it back to a javascript object. Example →
let obj1 = {name : "Vansh", address : {city : "Ranchi", state : "Jharkhand"}} let obj2 = JSON.parse(JSON.stringify(obj1)); obj2.address.city = "Jamshedpur" console.log(obj1.address.city) // Ranchi , original remains unchanged
Memory leaks and Garbage collector
Memory leaks occur when memory that is not needed is not released, leading to performance issues. Common causes of memory leaks :
Global variables - If there is no let, var or const used to assign a variable it automatically becomes a global variable and can lead to memory leaks.
function memLeak(){ name = "Vansh" // No var, let or const } memLeak()
Uncleared timers and intervals - If you do not clear setInterval() timers then it will lead to memory leaks.
let timer = setInterval(()=>{ console.log('Timer running....') }, 1000) clearInterval(timer) // it will prevent memory leak.
DOM references not cleared - If DOM references are not cleared, it will also lead to memory leak.
let elm = document.getElementById('btn'); elm.addEventListener('click', ()=>{ console.log('Button clicked...') }) elm = null // Old references remains in memory if not removed.
🗑️ Garbage Collection (GC) - Javascript uses automatic garbage collection via the Mark-and-Sweep algorithm. JavaScript automatically allocates memory when objects are created and frees it when they are not used anymore.
function gc(){
let obj = {name : "Vansh"} // Allocated in heap
}
// obj becomes unreachable after function execution, Garbage collector will remove it.
In order to read more about Garbage collection, you can visit this site https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management
How to avoid Memory leaks😎
Use let, var and const to avoid declaring variables as a global variable.
Remove event listeners when they are of no use.
Clear timers and intervals when not in use.
Use deep copies properly to avoid unnecessary memory allocation.
Conclusion
Understanding memory management and objects in Javascript is important for writing optimized and efficient code. By managing references properly and avoiding memory leaks, you can ensure your application run smoothly.🙂