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:
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:
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:
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:
// Manually dereference globalPerson
globalPerson = null;
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:
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).