Three types of memory leaking for JavaScript and two types of react.js issue
Undeclared or accidental global variables
if we don't set any var
let
const
it will turn to be global set, we can use 'use strict' to avoid it. the sample below
The undeclared variable creates a new variable within the global object. It causes a memory leak because the garbage collector cannot clear them.
error way
<script>
function init(){
bar = 'this is test';
}
</script>
correct way
<script>
function init(){
this.bar = 'this is test';
// or
var bar = 'this is test';
}
</script>
Forgotten timers or callbacks
if you accidentally use setTimeout
setInterval
in the function, they will keep calling
The undeclared variable creates a new variable within the global object. It causes a memory leak because the garbage collector cannot clear them.
- setTimeout and setInterval
<script>
var resource='default';
function init() {
setInterval(function(){
resource='setTime';
console.log(resource);
},1000);
}
resource=null;
</script>
This snippet does one thing: set resource value every 1 second. it cost memory leaks if you forget to clean your functional
event listener
Event listeners are attached to elements and remain in memory until explicitly removed. It causes a memory leak if an element with an attached event listener is removed from the DOM but not the listener.
Remove event listeners and unsubscribe whenever you no longer need them to avoid this problem.
var element = document.getElementById('button');
function onClick(event) {
element.innerHtml = 'text';
}
element.addEventListener('click', onClick);
// Do stuff
element.removeEventListener('click', onClick);
element.parentNode.removeChild(element);
// Now when element goes out of scope,
// both element and onClick will be collected even in old browsers that don't
// handle cycles well.
Closures
A key aspect of JavaScript development is closures: anonymous functions that capture variables from parent scopes
Any variables in the outer function that are being used in the inner function will remain in memory until the closure is released. Keep closures to a minimum and release them when you no longer need them.
error sample
var theThing = null;
var replaceThing = function () {
var originalThing = theThing;
var unused = function () {
if (originalThing)
console.log("hi");
};
theThing = {
longStr: new Array(1000000).join('*'),
someMethod: function () {
console.log(someMessage);
}
};
};
setInterval(replaceThing, 1000);
This snippet does one thing: every time replaceThing
is called, theThing
gets a new object which contains a big array and a new closure (someMethod
). At the same time, the variable unused
holds a closure that has a reference to originalThing
(theThing
from the previous call to replaceThing
). Already somewhat confusing, huh? The important thing is that once a scope is created for closures that are in the same parent scope, that scope is shared. In this case, the scope created for the closure someMethod
is shared by unused
. unused
has a reference to originalThing
. Even though unused
is never used, someMethod
can be used through theThing
. And as someMethod
shares the closure scope with unused
, even though unused
is never used, its reference to originalThing
forces it to stay active (prevents its collection). When this snippet is run repeatedly a steady increase in memory usage can be observed. This does not get smaller when the GC runs. essenially, a linked list of closures is created (with its root in the form of the theThing
variable), and each of these closures' scopes carries an indirect reference to the big array, resulting in a sizable leak.
additionally, react memory leak issue
Async operation & state update: Assume, the user first makes an API call to fetch the data. Then user clicks on some link, which navigates to another page before request is completed. Now as soon as the API request is complete, it will look for the state to get updated which no longer exists.
Infinite prefetching loop: UseEffect generally takes two arguments. The first is a callback function, and the second is a dependency array. When there is no second argument to
useEffect
, setting the state is repeated endlessly. As a result, memory leaks occur as system resources are drained.
Conclusion
in SPA framework, it starts to turn to be a problem for developing experience. this is a small tip to let me know what is the issue to cause my project doesn't have the unexpected issue.
Reference
https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/
https://dotblogs.com.tw/kinanson/2017/05/11/140022
https://www.linkedin.com/in/vidhya1706/recent-activity/shares/
https://shawnlin0201.github.io/JavaScript/JavaScript-Garbage-Collection/