Abinav Seelan
UI Engineer @Flipkart • Ex @hashnode & @SaltsideTech • Javascript Junkie & Pokemon League Champion from India. https://abinavseelan.com 🙃
and performance tuning your Javascript
@abinavseelan
blog.campvanilla.com
Allocate the memory
Use the allocated memory
Release the memory
// Allocation
let a = 10; // allocates memory to hold the value 10
const obj = { // Allocates memory for obj and extends that memory for each key
firstName: 'foo',
lastName: 'bar'
};
const arr = [1, 2, 3]; // Allocates memory for arr
const now = new Date(); // Allocation via function call
// Use
a = 20; // Modify the allocated memory
obj.birthday = new Date(); // Extend the allocated memory
Allocate the memory
Use the allocated memory
Release the memory
The
A garbage collector is a mechanism that helps reclaim unused memory
Reference Counts helps indicate when memory is unused
function someFunc() {
}
function someFunc() {
const someConst = 10;
// While inside the function someFunc,
// someConst has a reference to it
// hence the memory allocated to it
// will not be reclaimed
}
// Outside someFunc, someConst is not referenced
// and the Garbage collector cleans it up
const someConst = 10;
const obj = {
val: someConst // the constant someConst has a reference count of 1
}
const newObj = obj; // the object obj has a reference count of 1
newObj.newVal = someConst; // someConst has a reference count of 2
obj.val = 10;
// Here, someConst loses one reference count
// someConst has a reference count of 1
newObj = {
foo: 'bar'
}
// Here, both someConst and obj lose one reference.
// obj has a reference count of 0
// someConst has a reference count of 0
// Since both have a reference count of 0, they will be garbage collected!
// Example from MDN
function someFunc() {
const obj = {};
const newObj = {};
// Create a cyclic reference
obj.val = newObj;
newObj.val = obj;
}
// Even outside the function someFunc
// obj and newObj have 1 reference count
// and the garbage collector will not
// clean this up.
Reference Counts Unreachability helps indicate when memory is unused
Unreachable Code
Unreachable Code
A memory leak occurs when you don't need an object, but the runtime thinks you do and you're unintentionally using memory
A pretty common symptom of a memory leak is that a page's performance gets progressively worse over time.
function someFunc() {
b = 10; //looks pretty harmless right?
}
function someFunc() {
b = 10;
}
// is the same as
function someFunc() {
window.b = 10; // Oops!
// This happens due to scope lookup
// If the variable does not exist in any scope
// the JS runtime creates the variable
// in the GLOBAL scope! 😱
}
// The variable is never cleaned
setInterval(() => {
const someConst = 10;
// do something here
}, 1000);
// someConst may be cleaned at some point
// The handler itself is still referenced
// and will not be cleaned unless ...
// The fix? Assign the reference to a variable
let interval = setInterval(() => {
const someConst = 10;
// do something here
}, 1000);
// some code
// When you're done with the interval
clearInterval(interval);
// A trivial example
function someFunc() {
const a = 10; // 4 bytes, let's say
return function() {
console.log(a);
}
}
const arrayOfFunction = [];
for (let i = 0; i < 1000000, i++) {
arrayOfFunction[i] = someFunc();
}
// A real-world example
const inputField = document.getElementById('input-field');
function someFunc() {
// do something with inputField
}
// inputField is not longer referenced anywhere
// it can be cleaned.
// A real-world example
const inputField = document.getElementById('input-field');
const button = document.getElementById('cta');
button.addEventListener('click', () => {
// do something with inputField
});
// Here, it will not be cleaned since the runtime
// cannot decide when the memory allocated to
// inputField is not longer required
function someFunc() {
const a = 10;
const b = 20;
this.sendAlert = function() {
alert(a);
}
}
const btn = document.getElementById('cta');
btn.addEventListener('click', () => {
new someFunc().sendAlert();
// Only the memory allocated for `a` will not be cleaned.
});
A detached DOM tree is a DOM tree that is not part of the actual DOM tree, but is referenced by Javascript
Javascript
DOM
Javascript
DOM
DOM Node
Javascript
DOM
DOM Node
Reference
Javascript
DOM
DOM Node
Reference
let inputContainer = document.getElementById('input-field-1');
let button = document.getElementById('cta');
let inputBox = inputContainer.querySelect('input');
button.addEventListener('click', () => {
inputContainer.remove();
// removes the DOM node from the DOM tree
});
// But, it is still referenced in JS by inputBox
// This is a detached DOM tree.
const obj = {
numVal: 100, // 4 bytes
strVal: 'Hello World' // 11 bytes
}
const btn = document.getElementById('cta');
btn.addEventListener('click', () => {
alert(obj.numVal);
// This will hold on to 15 bytes
// not 4 bytes
});
Investigating leaks using
Chrome's
The
The
Build first, optimise after
Memory goes through a memory life-cycle
Garbage collectors use a mark-and-sweep algorithm to reclaim memory
Memory leaks are caused when the garbage collector and you as the programmer are basically ... not in sync.
Memory leaks cannot be found by a compiler/linter. You should take extra care to avoid them. :)
The most common causes for memory leaks are
To investigate a memory leak, first fire up the task manager to see the memory footprint
Use the dev tools to then narrow down the type of memory leak that is happening! :)
@abinavseelan
blog.campvanilla.com
By Abinav Seelan
Talk given at 1) Flipkart's UI Bootcamp, 2018 2) AngularJs & ReactJS Meetup on 21st Oct, 2017
UI Engineer @Flipkart • Ex @hashnode & @SaltsideTech • Javascript Junkie & Pokemon League Champion from India. https://abinavseelan.com 🙃