Click here to Skip to main content
15,346,923 members
Articles / Web Development / HTML
Article
Posted 2 Jul 2021

Tagged as

Stats

4.2K views
51 downloads
3 bookmarked

Detect Memory Leak on Web Browsers

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
2 Jul 2021CPOL4 min read
This is a note on how to detect memory leaks on web browsers.

Background

When you close the browser tab, all the memory is released. Memory leaks are most likely not big problems on web browsers. But if you have a long running application, it can be a problem. This is a note on how to detect memory leaks on web browsers. In this note, I will use examples to show how to use the memory capability on the development tools. I noticed that the development tools on Chrome and Edge are the most easy to use.

Take a Heap Snapshot

In Chrome or Edge development tools, we can take three kinds of memory profiles.

Image 1

In this note, I will be focusing on the "Heap snapshot", it is very effective to pinpoint exactly which object is causing the memory leakage. The test HTML page is the following:

HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
<style>
    
    button {
        height: 60px;
        border-radius: 5px;
        font-weight: 800;
        background-color: aquamarine;
    }
    
</style>
<title>Memory test - first attempt</title>
    
<script>
let MTestClassesArray = [];
    
class MTestClass {
    constructor() {}
}
    
const create_1000_objects = () => {
    for(let i = 0; i < 1000; i++) {
        MTestClassesArray.push(new MTestClass());
    }
    
    const text = `Total ${MTestClassesArray.length} `
        + `MTestClass objects created`;
    document.getElementById('divMsg').innerHTML = text;
};
    
</script>
    
</head>
    
<body>
    <button onclick="create_1000_objects()">
        Create 1000 MTestClass objects
    </button>
    <div id="divMsg" />
</body>
</html>
  • In this HTML page, we have a button.
  • Every click on the button, there are 1000 objects of type "MTestClass" created.
  • Each object is inserted into the array "MTestClassesArray".
  • Since the array "MTestClassesArray" is declared in the global scope, the objects are no longer garbage collectable.

To verify the above statements, let us load the page and click on the button a few times. In my experiment, I used Edge.

Image 2

As it is indicated in the page, I have clicked the button 3 times and 3000 "MTestClass" objects have been created. We can bring up the development tool by "CTRL+SHIFT+i". Before taking the memory snapshot, let us first force a garbage collection.

Image 3

We can then take a memory snapshot after the garbage collection.

Image 4

The memory snapshot gives us great visibility to the memory heap.

  • We can filter the snapshot to check if objects of certain class type are in the memory heap. In our example, we can see exactly 3000 "MTestClass" objects.
  • We can also see what object is preventing the "MTestClass" objects being garbage collected. In our example, it is the "MTestClassesArray" object.

The development tool can even tell us which line of code created the "MTestClass" objects.

Image 5

A Real-World Example - AsyncSubject

If you subscribe to an event, you need to un-subscribe it. If not, it will be very likely be a memory leak. But is it the case for the "AsyncSubject" in rxjs?

HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
<style>
    
    button {
        height: 60px;
        border-radius: 5px;
        font-weight: 800;
        background-color: aquamarine;
    }
    
</style>
<title>Memory test - async subject</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.1.0/rxjs.umd.js"></script>
    
<script>
const get_time = () => {
    const element = document.getElementById('divTime');
    const subject = new rxjs.AsyncSubject();
    
    element.innerHTML = '';
    
    setTimeout(() => {
        subject.next(new Date());
        subject.complete();
    
    }, 3 * 1000);
    
    subject.subscribe((data) => {
        element.innerHTML = data.toString();
    });
};    
    
</script>
</head>
    
<body>
    <button onclick="get_time()">Get Time by AsyncSubject</button>
    <div id="divTime"></div>
</body>
</html>
  • In this HTML page, we have a button.
  • Clicking on the button, the current time will be displayed on the page.
  • Instead of getting the time directly, I created an "AsyncSubject" and the time is obtained in a timer callback function.
  • The program then "subscribe" to the "AsyncSubject" and display it on the page.

It should be noted that the "AsyncSubject" is created in the "get_time" arrow function, so it is not associated to any global context. I will assume that it is garbage collectable after the timer callback. But let us confirm it is using the development tool.

Image 6

There is a 3 second delay between the button click and when the time is displayed. In order to confirm that the "AsyncSubject" is garbage collectable, let us take two heap snapshots. One before the timer callback and one after the timer callback.

Image 7

Before the timer callback, we can find the "AsyncSubject" in the memory heap. At this time, it is not garbage collectable because it is retained by some other resources and eventually reachable from the window object.

Image 8

But after the timer callback, the "AsyncSubject" is collected. If it is not collected, you can manually force a collection. With this example, we can have better confidence on our program. If the "AsyncSubject" is used correctly, we do not need to un-subscribe the event.

Additional Note

  • It has been noted that if you ever "console.log()" an object, it is no longer garbage collectable. In a production release, you should keep it in mind, if you have memory problems.
  • When searching for objects in the heap snapshot, the name of the class can be changed by a minifier, if your program is minified.

Points of Interest

  • This is a note on how to detect memory leaks on web browsers.
  • The development tool can be very useful for us to have some visibility to the memory heap.
  • I hope you like my postings and I hope this note can help you one way or the other.

History

  • 30th June, 2021: First revision

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dr. Song Li
United States United States
I have been working in the IT industry for some time. It is still exciting and I am still learning. I am a happy and honest person, and I want to be your friend.

Comments and Discussions

 
QuestionExcellent Post Pin
TJ Bandrowsky5-Jul-21 10:08
MemberTJ Bandrowsky5-Jul-21 10:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.