javascriptThe column introduces the garbage collection mechanism, memory leaks, and closure contents. Let’s take a look at the fast-end bench.
Write at the front: This is a series I am about to start writing in the javascript column, mainly in the framework of rampant In the era, although I use a framework for work, for interviews and technical advancement, the basic knowledge of JS is the icing on the cake, and it is also a piece of knowledge that I have to learn. Although you don’t need to know a lot about cars to drive a car, you only need to master the common uses of cars. Just function. But if you know cars, you can drive better, and by the same token. Of course, an article will not just talk about one knowledge point. Generally, related knowledge points will be connected in series. While recording your own learning, you will share your own learning and encourage each other! If you can, please also please give me a like, your likes will also make me work harder to update!
The previous blog mainly explains the allocation and use of memory (stack memory and heap memory, deep copy and shallow copy). After use, of course, Returning unused memory is like clearing unused software on your phone from the background, which can improve the running speed of your phone. Otherwise, if more and more memory is used, it will get stuck sooner or later. The same goes for JS
.
Every once in a while, the garbage collector
of JS will "patrol" the variables, just like security patrols in the park, letting irrelevant people leave quickly . When a variable is no longer needed, it will release the memory space occupied by the variable. This process is called Garbage Collection
JS
Garbage There are two types of recycling algorithms, reference counting and mark clearing.
The reference counting method is the most basic garbage collection algorithm and has been used by modern browsers. The equipment has been eliminated. Before learning the reference counting method, you need to first have a certain concept of reference. You can think of it as a description of the memory address pointed to by the current variable, which is somewhat similar to the memory pointer of the JS reference data type. To understand the concept, let’s first look at a line of code:
var obj={name:'jack'};复制代码
When we assign a value to obj
, we actually create a reference pointing to the variable, reference count is 1, Under the mechanism of reference counting, each value in the memory will correspond to a reference count
, and when we assign a value to obj
, it is When null
, this variable becomes a piece of useless memory. At this time, the reference count of obj
will become 0, and it will be garbage collected. The memory space occupied by obj
will be released
We know that the life cycle of the function scope is very short. After the function is executed, the memory space inside Variables are basically useless variables. The consequence of not clearing them is that the memory garbage is not released, and it still occupies the original memory and does not let go, which will easily cause memory leak. Let’s first look at a piece of code and Running results:
function changeName(){ var obj1={}; var obj2={}; obj1.target=obj2; obj2.target=obj1; obj1.age=15; console.log(obj1.target); console.log(obj2.target); } changeName();复制代码
and
obj2.target have mutual references. situation, because when
obj1.age is changed,
obj1.target.age and
obj2.target.age are also affected at the same time, and they point to The reference count is consistent
When the function is executed, obj1 and
obj2 are still alive and well, because
obj1.target and ## After the execution of #obj2.target
is completed, the reference count is still 1
. It is clear that the function has been executed, but this kind of garbage still exists. There are too many such functions defined, Memory leakIt will also be unavoidable
, it is mainly divided into two stages, marking stage and clearing stage:
The garbage collector will start from the root object (Window object) and scan all reachable objects. This is the so-called
reachable) are objects that are considered unnecessary and will be cleared as garbage
现在再来看下上面的代码
function changeName(){ var obj1={}; var obj2={}; obj1.target=obj2; obj2.target=obj1; obj1.age=15; console.log(obj1.target); console.log(obj2.target); } changeName();复制代码
在函数执行完毕之后,函数的声明周期结束,那么现在,从 Window对象
出发, obj1
和 obj2
都会被垃圾收集器标记为不可抵达,这样子的情况下,互相引用的情况也会迎刃而解。
该释放的内存垃圾没有被释放,依然霸占着原有的内存不松手,造成系统内存的浪费,导致性能恶化,系统崩溃等严重后果,这就是所谓的内存泄漏
闭包是指有权访问另一个函数作用域中的变量的函数。至于为什么有权访问,主要是因为作用域嵌套作用域,也就是所谓的作用域链,关于作用域链不清楚的可以看我的第一篇博客一文搞懂JS系列(一)之编译原理,作用域,作用域链,变量提升,暂时性死区,就是因为作用域链的存在,所以内部函数才可以访问外部函数中定义的变量 ,作用域链是向外不向内的,探出头去,向外查找,而不是看着锅里,所以外部函数是无法访问内部函数定义的变量的。并且,还有一个特性就是将闭包内的变量始终保持在内存中。
前面的作用域向外不向内,这里就不再做过多解释了,我们主要来看我后面说的特性,那就是闭包内的变量始终保存在内存中
来看一下阮一峰教程当中的一个例子
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ console.log(n); } return f2; } var result=f1(); //等同于return f2(); result(); // 999 nAdd(); result(); // 1000 nAdd(); result(); // 1000复制代码
从输出结果就可以看得出来,这个变量 n
就一直保存在内存中,那么,为什么会这样子呢,我们现在就来逐步地分析代码
① 首先 f1()
作为 f2()
的父函数,根据作用域链的规则, nAdd()
方法以及 f2()
方法中可以正常访问到 n
的值
② f2()
被赋予了一个全局变量,可能这里大家就会开始产生疑惑了,这个 f2()
不是好好地定义在了 f1()
函数中吗,这不是扯淡吗,那么,先看下面的这句 var result=f1();
,这个 result
很明显是被赋予了一个全局变量,这应该是没有任何争议的,那么,接着来看这个 f1()
,可以看到最后,是一句 return f2;
,看到这里,想必大家也已经想明白了,这个 f2()
被赋予了一个全局变量
③ 已经明白了上面的这一点以后,根据上面垃圾回收机制所提及到的标记清除法,这个 f2()
始终是可以被根对象 Window
访问到的,所以 f2 将始终存在于内存之中,而 f2 是依赖于 f1 ,因此 f1 也将始终存在于内存当中,那么, n
的值也就自然始终存在于内存当中啦
④ 还有一点需要注意的就是为什么我们可以直接执行 nAdd()
,这是因为在 nAdd()
的前面没有使用 var
,因此 nAdd()
是一个全局函数而不是局部函数
所以,闭包的变量会常驻内存,滥用闭包容易造成内存泄漏,特别是在 IE 浏览器下,2020年了,应该没人使用 IE 了吧(小声bb),解决办法就是在退出函数之前,将不使用的局部变量全部删除,这也是上面讲了垃圾回收机制 => 内存泄漏,再讲到闭包的原因,我会尽量将有关联性的知识点一起讲了,也方便大家学习和加深印象。
相关免费学习推荐:javascript(视频)
The above is the detailed content of Understand the garbage collection mechanism, memory leaks, and closures of JS series (3) with one piece of paper. For more information, please follow other related articles on the PHP Chinese website!