JS Memory Management

Lecture



Introduction

Low-level programming languages ​​(for example, C) have low-level primitives for memory management, such as malloc() and free() . In JavaScript, memory is allocated dynamically when creating entities (ie, objects, strings, etc.) and is “automatically” released when they are no longer used. The latter process is called garbage collection . The word “automatically” is a source of confusion and often creates a javascript programmer (and other high-level languages) with a false sense that they may not care about memory management.

Memory life cycle

Regardless of the programming language, the life cycle of the memory is almost always the same:

  1. Allocation of required memory.
  2. Its use (read, write).
  3. Freeing allocated memory when it is no longer necessary.

The first two items are implemented explicitly (that is, directly by the programmer) in all programming languages. The third clause is implemented explicitly in low-level languages, but in most high-level languages, including JavaScript, it is done automatically.

JavaScript memory allocation

Memory allocation when initializing variable values

In order not to bother the programmer with the care and low-level memory allocation operations, the JavaScript interpreter dynamically allocates the necessary memory when declaring variables:

 var n = 123; // выделяет память для типа number var s = "azerty"; // выделяет память для типа string var o = { a: 1, b: null }; // выделяет память для типа object и всех его внутренних переменных var a = [1, null, "abra"]; // (like object) выделяет память для array и его внутренних значений function f(a){ return a + 2; } // выделяет память для function (которая представляет собой вызываемый объект) // функциональные выражения также выделяют память под object someElement.addEventListener('click', function(){ someElement.style.backgroundColor = 'blue'; }, false); 

Memory allocation when function calls

Calls to some functions also lead to the allocation of memory for an object:

 var d = new Date(); var e = document.createElement('div'); // выделяет память под DOM элемент 

Some methods allocate memory for new values ​​or objects:

 var s = "azerty"; var s2 = s.substr(0, 3); // s2 это новый объект типа string // Т.к. строки - это постоянные значения, интерпретатор может решить, что память выделять не нужно, но нужно лишь сохранить диапазон [0, 3]. var a = ["ouais ouais", "nan nan"]; var a2 = ["generation", "nan nan"]; var a3 = a.concat(a2); // новый массив с 4 элементами в результате конкатенации элементов 'a' и 'a2' 

Use of values

"Using values", as a rule, means reading and writing values ​​from / to the memory area allocated for them. This happens when reading or writing the value of a variable, or a property of an object, or even when passing an argument to a function.

Freeing memory when it is no longer needed

It is at this stage that most of the problems in the field of "memory management" appear. The most difficult task in this case is a clear definition of the moment when "allocated memory is no longer needed." Often, the programmer himself must determine that in this place of the program this part of the memory is no longer needed and free it.

High-level language interpreters are equipped with embedded software called "garbage collector", whose task is to monitor the allocation and use of memory and, if necessary, to automatically free up unnecessary chunks of memory. This happens quite roughly, since the main problem of accurately determining the moment when any part of the memory is no longer needed is insoluble (i.e., this problem cannot be solved by a unique algorithmic solution).

Garbage collection

As mentioned above, the problem of accurately determining when any part of the memory is “no longer needed” is uniquely unsolvable. As a result, garbage collectors solve the task only partially. In this section, we will explain the fundamental points needed to understand the principle of operation of the main algorithms for garbage collection and their limitations.

Links

Most garbage collection algorithms are based on the concept of reference . In the context of memory management, an object is considered to refer to another object if the first has access to the second (whether it is explicit or implicit). For example, each JavaScript object has a link to its prototype (implicit link) and links to the values ​​of its fields (explicit links).

In this context, the concept of "object" is understood somewhat more broadly than for typical JavaScript objects and additionally includes the concept of function scopes (or global lexical scope)

Garbage collection based on reference counting

This is the most primitive garbage collection algorithm, narrowing down the concept “an object is no longer needed” to “for this object, there are no other objects that refer to it”. An object is considered to be destroyed by the garbage collector if the number of references to it is zero.

Example

 var o = { a: { b:2 } }; // создано 2 объекта. Один ссылается на другой как на одно из своих полей. // Второй имеет виртуальную ссылку, поскольку присвоен в качестве значения переменной 'o'. // Очевидно, что ни один из них не подлежит сборке мусора. var o2 = o; // переменная 'o2' - вторая ссылка на объект o = 1; // теперь объект, имевший изначально ссылку на себя из 'o' имеет уникальную ссылку через переменную 'o2' var oa = o2.a; // ссылка на поле 'a' объекта. // Теперь на объект 2 ссылки: одна на его поле и вторая - переменная 'oa' o2 = "yo"; // Объект, на который изначально ссылалась переменная 'o', теперь имеет ноль ссылок на неё. // Может быть уничтожен при сборке мусора. // Однако, на его поле 'a' всё ещё ссылается переменная 'oa', так что удалять его ещё нельзя oa = null; // оригинальное значение поля объекта 'a' в переменной o имеет ноль ссылок на себя. // можно уничтожить при сборке мусора. 

Restriction: circular links

The main limitation of this naive algorithm is that if two objects refer to each other (thus creating a circular reference), they cannot be destroyed by the garbage collector, even if "no longer needed".

 function f(){ var o = {}; var o2 = {}; oa = o2; // o ссылается на o2 o2.a = o; // o2 ссылается на o return "azerty"; } f(); // Создаётся два ссылающихся друг на друга объекта, что порождает циклическую ссылку. // Они не будут удалены из области видимости функции после завершения работы этой функции, // таким образом, сборщик мусора не сможет их удалить, несмотря на их очевидную ненужность. // Так как сборщик мусора считает, что, раз на каждый из объектов существует как минимум одна ссылка, // то уничтожать их нельзя. 

Real life example

Internet Explorer 6, 7 browsers have a garbage collector for DOM objects, which works on the principle of reference counting. Therefore, these browsers can easily be forced to cause systematic memory leaks (memory leaks) as follows:

 var div = document.createElement("div"); div.onclick = function(){ doSomething(); }; // div имеет ссылку на обработчик события через свойство 'onclick'. // Обработчик также ссылается на div, поскольку переменная 'div' доступна из области видимости функции. // Таким образом, оба объекта не могут быть уничтожены сборщиком мусора и порождают утечку памяти. 

Algorithm "Mark-and-sweep"

This algorithm narrows down the concept of "an object is no longer needed" to "an object is not available."

It is based on the concept of a collection of objects called roots (in JavaScript, the root is a global object). The garbage collector runs periodically from these roots, first finding all the objects referenced by roots, then all the objects referenced from those found, and so on. Starting from roots, the garbage collector thus finds all available objects and destroys inaccessible ones.

This algorithm is better than the previous one, since "zero object references" is always included in the concept "object is not available." The reverse is not true, as we have just seen above using the example of circular references.

Starting in 2012, all modern web browsers are equipped with garbage collectors that operate solely on the principle of mark-and-sweep ("mark and throw away"). All the improvements in garbage collection in JavaScript interpreters (genealogical / incremental / competitive / parallel garbage collection) over the past few years are improvements to this algorithm, but not new garbage collection algorithms, since further narrowing of the concept "object is no longer needed" is not possible .

Now circular links are not a problem.

In the first example above, after returning from a function, both objects have no references to themselves accessible from the global object. Accordingly, the garbage collector will mark them as inaccessible and then delete.

The same applies to the second example. As soon as the div and its handler become inaccessible from the roots, they will both be destroyed by the garbage collector, despite the presence of circular references to each other.

Restriction: some objects need an explicit sign of unavailability

Although this particular case is regarded as a limitation, but in practice it is extremely rare, therefore, in most cases, you do not need to worry about garbage collection.

In JavaScript, where there is no need to manually free the memory, a technology called garbage collection is implemented. The JavaScript interpreter may detect that the object will never be used by the program again. Having determined that the object is unavailable (i.e., there is no longer any way to get a reference to it), the interpreter finds out that the object is no longer needed, and its memory can be freed.2 Consider the following lines of code:

var s = "hello"; // allocate memory for the string

var u = s.toUpperCase (); // Create a new line

s = u; // rewrite the link to the original string

After the operation of this code, the original string "hello" is no longer available - there is no reference to it in any of the program variables. The system detects this fact and frees the memory. Garbage collection is automatic and invisible to the programmer. About garbage collection, he should know exactly as much as he needs to trust his work - he should not think about where all the old objects were.

created: 2014-10-07
updated: 2021-03-13
132501



Rating 9 of 10. count vote: 2
Are you satisfied?:



Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Scripting client side JavaScript, jqvery, BackBone

Terms: Scripting client side JavaScript, jqvery, BackBone