Home > Web Front-end > JS Tutorial > Detailed analysis of javascript garbage collection mechanism and memory leaks_javascript skills

Detailed analysis of javascript garbage collection mechanism and memory leaks_javascript skills

WBOY
Release: 2016-05-16 17:16:27
Original
948 people have browsed it

Javascript has an automatic garbage collection mechanism, which means that the execution environment is responsible for managing the memory used during code execution. In languages ​​like C and C++, a fundamental task for developers is to manually track memory usage, which is a source of many problems. When writing JavaScript programs, developers no longer need to worry about memory usage. The allocation of required memory and useless recycling are fully automated. The principle of this garbage collection mechanism is actually very simple: find those variables that are no longer used, and then release the memory occupied by them. To do this, the garbage collector will perform this operation periodically according to a fixed time interval (or a collection time preset in the code execution).

Let’s analyze the normal life cycle of local variables in functions. Local variables only exist during function execution. In this process, corresponding space will be allocated on the stack (or heap) memory for local variables in order to store their values. These variables are then used in the function until the function execution ends. At this point, the local variables no longer need to exist, so their memory can be released for future use. In this case, it is easy to determine whether the variable is still necessary; but this conclusion is not so easy in all cases. The garbage collector must keep track of which variables are useful and which are not, and mark variables that are no longer useful so that the memory they occupy can be reclaimed in the future. The strategy used to identify useless variables may vary depending on the implementation, but depending on the implementation in the browser, there are usually two strategies.

Mark Clear

The most commonly used garbage collection method in JavaScript is mark-and-sweep. When a variable enters the environment (for example, when you declare a variable in a function), the variable is marked as "entered the environment". Logically, the memory occupied by variables entering the environment can never be released, because they may be used whenever the execution flow enters the corresponding environment. And when a variable leaves the environment, this marks it as "leaving the environment".

Variables can be marked in any way. For example, you can flip a special bit to record when a variable enters the environment, or use a list of variables "entering the environment" and a list of variables "leaving the environment" to track which variables have changed. At the end of the day, it doesn’t really matter how you mark variables, but what strategy you adopt.

When the garbage collector runs, it will mark all variables stored in memory (of course, any marking method can be used). Then, it removes the variables in the environment and the variable tags referenced by variables in the environment. Variables that are marked after this will be regarded as variables to be deleted because variables in the environment can no longer access these variables. Finally, the garbage collector completes the memory cleanup work, destroying those marked values ​​and reclaiming the memory space they occupy.

As of 2008, the JavaScript implementations of IE, Firefox, Opera, Chrome, and Safari all use mark-and-sweep garbage collection strategies (or similar strategies), but the garbage collection intervals are different.

Reference Count

Another less common garbage collection strategy is called reference counting. The meaning of reference counting is to track the number of times each value is referenced. When you declare a variable and assign a reference type value to the variable, the number of references to this value is 1. If the same value is assigned to another variable, the reference count of the value is increased by 1. On the contrary, if the variable containing a reference to this value obtains another value, the number of references to this value is reduced by 1. When the number of references to this value becomes 0, it means that there is no way to access this value, so it can be The occupied memory space is reclaimed. Then the next time the garbage collector runs, it will free the memory occupied by values ​​with zero references.

Netscape Navigator 3.0 was the first browser to use a reference counting strategy, but soon it encountered a serious problem: circular references. A circular reference means that object A contains a reference to object B, and object B also contains a reference to object A.

Please see the following example:

Copy the code The code is as follows:

function () {
var objectA = new Object();
var objectB = new Object();

objectA.someOtherObject = objectB;
objectB.anotherObject = objectA;
}

In this example, objectA and objectB refer to each other through their respective properties, that is, the number of references of both objects is 2. In an implementation that uses index clearing, both objects leave the scope after the function is executed. So the two referencing each other is not a problem. But in an implementation that uses a reference counting strategy, objectA and objectB will continue to exist after the function is executed, so their number of references will never be 0. If this function is called repeatedly, a large amount of memory will not be recycled. Therefore, Netscape abandoned the reference counter method in Navigator 4.0 and instead used mark clearing to implement its garbage collection mechanism. However, the troubles caused by reference counting do not end there.

We know that some objects in IE are not native javascript objects. For example, the objects in the BOM and DOM are implemented in the form of COM (Component Object Model) objects using C, and the garbage collection mechanism of COM objects uses a reference counting strategy. Therefore, even though IE's JavaScript engine is implemented using the mark-and-clear strategy, the COM objects accessed by JavaScript are still based on the reference counting strategy. In other words, as long as COM objects are designed in IE, there will be circular reference problems.

The following simple example shows the circular reference problem caused by using COM objects:

Copy code The code is as follows:

var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element .somObject = myObject;

This example creates a circular reference between a DOM element (element) and a native JavaScript object (myObject). Among them, the variable myObject has a property named element that points to the element object; and the variable element also has a property named someObject that points back to myObject. Because of this circular reference, even if the DOM in the example is removed from the page, it will never be recycled.

In order to avoid circular reference problems like this, it is best to manually disconnect the native JavaScript objects from the DOM elements when they are not used. For example, you can use the following code to eliminate the circular reference created by the previous example:

Copy the code The code is as follows:

myObject.element = null;
element.somObject = null;

Setting a variable to null means severing the connection between the variable and the value it previously referenced. But the next time the garbage collector runs, these values ​​will be deleted and the memory they occupy will be reclaimed.

Performance issues

Garbage collectors run periodically, and if the amount of memory allocated for variables is objective, the recycling workload is also quite large. In this case, determining the garbage collection interval is a very important issue. When it comes to how often the garbage collector runs, it's hard not to think of the performance issues IE is notorious for. IE's garbage collector runs based on the memory allocation, specifically 256 variables, 4096 object (or array) literals and array elements (slots), or 64KB strings. When any of the above thresholds are reached, the garbage collector will run. The problem with this implementation is that if a script contains that many variables, it is likely that the script will maintain that many variables throughout its life. As a result, the garbage collector may have to run frequently. As a result, severe performance issues were caused by the initial IE7 rewrite of its garbage collection routines.

With the release of IE7, the garbage collection routine of its JavaScript engine has changed the way it works: the critical values ​​of variable allocations, literals and/or array elements that trigger garbage collection are adjusted to dynamic corrections. The thresholds in IE7 are equal to those in IE6 when initialized. If the routine reclaims less than 15% of the allocated memory, the threshold for variables, literals, and/or array elements is doubled. If the routine reclaims 85% of the allocated memory, various thresholds are reset to their default values. This seemingly simple adjustment greatly improves IE's performance when running pages containing a lot of JavaScript.

In fact, the garbage collection process can be triggered in some browsers, but we do not recommend readers to do this. In IE, calling the window.CollectGarbage() method will immediately point to garbage collection. In Opera7 and higher, calling window.opera.collect() will also start the garbage collection routine.

Manage memory

By writing programs in a language with a garbage collection mechanism, developers generally do not have to worry about memory management issues. However, the problems faced by JavaScript in memory management and garbage collection are still a bit different. One of the most important issues is that the amount of usable memory allocated to web browsers is usually less than that allocated to desktop applications. The purpose of this is mainly for security reasons, and the purpose is to prevent web pages running javascript from exhausting all system memory and causing the system to crash. Memory limit issues not only affect the allocation of memory to variables, but also affect the call stack and the number of statements that can be executed simultaneously in a thread.

Therefore, ensuring that the page takes up the least amount of memory can give the page better performance. It is best to release its reference by setting its value to null - this practice is called dereferencing. This approach is used for most global variables and properties of global objects. Local variables are automatically dereferenced when they execute the environment, as shown in the following example:

Copy code The code is as follows:

function createPerson (name) {
var localPerson = new Object();
localPerson.name = name;
return localPerson;
};
var gllbalPerson = createPerson("Nicholas");

// Manually dereference globalPerson
globalPerson = null;


In this example, the variable globalPerson obtains the value returned by the createPerson() function. Inside the createPerson() function, we create an object and assign it to the local variable localPerson, and then add a property named name to the object. Finally, when this function is called, localPerson is returned as a function and assigned to the global variable globalPerson. Since localPerson leaves its execution environment after the createPerson() function is executed, there is no need for us to explicitly dereference it. But for the global variable globalPerson, we need to manually dereference it when we are not using it. This is the purpose of the last line of code in the above example.

However, dereferencing a value does not mean automatically recycling the memory occupied by the value. What dereferencing really does is take the value out of the execution environment so that the garbage collector can reclaim it the next time it runs.

Memory leak

Closures cause some special problems in IE because IE uses different garbage collection routines for JScript objects and COM objects. Specifically, if an HTML element is stored in the closure's scope chain, it means that the element cannot be destroyed. Let’s look at the following example:

Copy the code The code is as follows:

function assignHandler () {
var element = document.getElementById("someElement");
element.onclick = function () {
alert(element.id);
};
};

The above code creates a closure as the element time handler, and this closure creates a circular reference. Since the anonymous function saves a reference to the active object of assignHandler(), the number of references to element cannot be reduced. As long as the anonymous function exists, the reference number of element is at least 1, so the memory it occupies will never be recycled. However, this problem can be solved by slightly rewriting the code as follows:
Copy the code The code is as follows:

function assignHandler () {
var element = document.getElementById("someElement");
var id = element.id;

element.onclick = function () {
            alert(id);
   };

     element = null; in a variable, and referencing that variable in the closure eliminates the circular reference. But just doing this step still cannot solve the problem of memory leaks. It must be remembered that the closure refers to the entire activity object containing the function activity, which contains the element. Even if the closure does not refer to the element directly, a reference is still saved in the active object containing the function. Therefore, it is necessary to set the element variable to null. In this way, the reference to the DOM object can be released, the number of references can be successfully reduced, and the memory occupied by it can be properly recycled.


Description

1. If you keep the reference of an object in that window in another window, the memory will not be released even if you close the window;

2. What’s worse is that if you keep a reference to a DOM object and close the window where the object is located, IE will crash and report a memory error (or require a restart).

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template