Search code examples
javascriptperformancememory-leaksgoogle-chrome-devtoolsv8

Why chrome task manager memory footprint increases dramatically(170mb) on rendering just 10mb string in only one div's innerHTML?


I've did a small test where I create a 10mb string on a button click. And then on a second button click I render that string content in a div's innerHTML.

The code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test</title>

</head>
<body>
    <button id="btn-load">Load string</button>
    <button id="btn-render">Render string</button>
    <div id="place-to-render"></div>
    <script type="module" src="main.js"></script>
</body>
</html>

JS main.js :

let data;
function createBigString() {
    data = new Array(10000000).join('x'); //10mb
    console.log('created object',data);
}

function render() {
    const placeToRender = document.getElementById('place-to-render');
    placeToRender.innerHTML = data;
    console.log('rendered');
}
document.getElementById('btn-load').addEventListener('click', createBigString);
document.getElementById('btn-render').addEventListener('click', render);

As explained in this answer

The Memory Footprint column matches the number of MB reported for the Memory column of the process within the Task Manager or Activity Monitor.

Meaning the actual RAM taken from the OS for this specific tab on chrome. Can be seen in chrome task manager.

Memory Tests I did (Incognito) :

I've recorded a Heap snapshot after creating the string (and assigning it to the global variable data).

  • The heap snapshot was 11MB,
  • The Memory footprint value was 51mb (after taking the snapshot).

Then I clicked on the render string button, and after the string was loaded to the screen I took another snapshot.

  • The heap snapshot was 1MB.
  • The Memory footprint surprisingly rose all the way to 222mb. (173mb difference on a 10mb string render in one node), and it stays like that, it doesn't drop down after a manual GC.

Questions:

  • So I wonder why there is such a big leap in memory footprint although the size of the string is only 10mb ?
  • What exactly does the memory FP contain beside the sum of the JS memory + media files + DOM Nodes ?
  • Is there any place to read about how and by which factors the memory footprints allocates compared to live JS memory ?
  • Is there any performance tool I can use to analyze the memory footprint ?
  • And also I'm not sure why the second snapshot of the live JS went from 10mb to 1mb, if still the values are saved on the global data variable, therefore GC should not clean it, am I right?

Solution

  • why there is such a big leap in memory footprint although the size of the string is only 10mb ?

    The pixels needed to draw a string with 10 million characters onto your screen require a lot more than 10 MB.

    What exactly does the memory FP contain beside the sum of the JS memory + media files + DOM Nodes ?

    The entire renderer process' memory. Off the top of my head, that includes various libraries, fonts, the "picture" that is the result of the rendering process, and all sorts of temporary memory for ongoing tasks.

    Unfortunately, I'm not aware of any documentation or tools to learn more about these details; of course that doesn't mean that none exist (see e.g. wOxxOm's comment).

    why the second snapshot of the live JS went from 10mb to 1mb, if still the values are saved on the global data variable, therefore GC should not clean it, am I right?

    Yes, the GC didn't collect the string. The backing stores of strings (i.e. the actual characters) can be handed back and forth between V8 and Blink. In this case, apparently the character contents were transferred over to being Blink's responsibility, so they are no longer part of the JavaScript heap (though the String object on the JS heap still refers to them), yet they are still part of the process' overall memory footprint.