javascript 칼럼에서는 가비지 수집 메커니즘, 메모리 누수 및 클로저 내용을 모두에게 소개합니다.
Written at the front: 이것은 주로 프레임워크가 만연한 시대에 javascript 칼럼에 쓰기 시작하는 시리즈입니다. 업무용, 인터뷰용, 기술 발전용으로 프레임워크를 사용하지만, JS의 기본 지식은 금상첨화이며 꼭 배워야 할 지식이기도 합니다. 자동차를 운전하는 사람은 자동차에 대해 많이 알 필요는 없지만 자동차의 일반적인 기능만 익히면 됩니다. . 하지만 자동차를 안다면 운전을 더 잘할 수 있습니다. 물론, 기사는 단지 하나의 지식 포인트에 대해서만 이야기하는 것이 아닙니다. 일반적으로 관련된 지식 포인트가 시리즈로 연결되어 자신의 학습을 기록하면서 자신의 학습을 공유하고 서로 격려하게 됩니다! 가능하시다면 좋아요도 부탁드려요, 여러분의 좋아요 덕분에 저도 업데이트하는데 더 힘이 됩니다!
이전 블로그에서는 주로 메모리(스택 메모리 및 힙 메모리, 딥 카피 및 얕은 카피)는 물론 사용 후에는 사용하지 않은 메모리를 반환해야 합니다. 마치 휴대폰에서 사용하지 않는 소프트웨어를 백그라운드에서 삭제하는 것과 마찬가지로 실행 속도를 향상시킬 수 있습니다. 그렇지 않으면 더 많이 사용할수록 조만간 정체될 것입니다. JS
도 마찬가지입니다. JS
也是一样的。
每隔一段时间, JS
的垃圾收集器都会对变量进行“巡逻”,就和保安巡逻园区一样,让不相干的人赶紧走。当一个变量不被需要了以后,它就会把这个变量所占用的内存空间所释放,这个过程就叫做垃圾回收
JS
的垃圾回收算法分为两种,引用计数法和标记清除法
引用计数法是最初级的垃圾回收算法,已经被现代浏览器所淘汰了。在学习引用计数法之前,需要首先对引用有一定的概念,你可以认为它就是对当前变量所指向的那块内存地址的描述,有点类似于JS引用数据类型的内存指向的概念,先来看一行代码:
var obj={name:'jack'};复制代码
当我们在给 obj
赋值的同时,其实就创建了一个指向该变量的引用,引用计数为1,在引用计数法的机制下,内存中的每一个值都会对应一个引用计数
而当我们给 obj
赋值为 null
时,这个变量就变成了一块没用的内存,那么此时, obj
的引用计数将会变成 0,它将会被垃圾收集器所回收,也就是 obj
所占用的内存空间将会被释放
我们知道,函数作用域的生命周期是很短暂的,在函数执行完毕之后,里面的变量基本是没用的变量了,不清除的后果就是该内存垃圾没有被释放,依然霸占着原有的内存不松手,就会容易引发内存泄漏,先来看一段代码以及运行结果:
function changeName(){ var obj1={}; var obj2={}; obj1.target=obj2; obj2.target=obj1; obj1.age=15; console.log(obj1.target); console.log(obj2.target); } changeName();复制代码我们可以看到,
obj1.target
和 obj2.target
存在互相引用的情况,因为在改变 obj1.age
的同时,obj1.target.age
和 obj2.target.age
也同时都被影响到了,它们所指向的引用计数是一致的在函数执行完毕的时候, obj1
和 obj2
还是活的好好地,因为 obj1.target
和 obj2.target
가끔 JS
의 Garbage Collector는 공원을 순찰하는 경비원처럼 변수를 "순찰"하여 관련 없는 사람들을 빠르게 떠나게 합니다. 변수가 더 이상 필요하지 않으면 변수가 차지하는 메모리 공간을 해제합니다. 이 프로세스를 garbage collection
JS
의 가비지 수집 알고리즘은 두 가지 유형으로 나누어집니다. 및 마크 지우기
function changeName(){ var obj1={}; var obj2={}; obj1.target=obj2; obj2.target=obj1; obj1.age=15; console.log(obj1.target); console.log(obj2.target); } changeName();复制代码
obj
에 값을 할당하면 실제로 참조 개수가 1인 변수를 가리키는 reference그리고 obj
를 null
에 할당하면 이 변수는 쓸모없는 메모리 조각, 그러면 이때 obj
의 참조 횟수는 0이 되고 가비지 컬렉터에 의해 재활용됩니다. 즉, obj가 차지하는 메모리 공간입니다.
가 출시됩니다
가 발생하기 쉽습니다. 먼저 코드 일부와 실행 결과를 살펴보겠습니다. 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复制代码
obj1.target
과 obj2.target
이 서로를 참조하는 것을 볼 수 있습니다. obj1.age
일 때 >가 변경되면 obj1.target.age
와 obj2.target.age
도 동시에 영향을 받습니다. 실행 시 obj1
및 obj2
는 여전히 살아 있습니다. obj1.target
및 obj2.target
의 참조 카운트 때문입니다. > 실행 후에도 여전히 1
现在再来看下上面的代码
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(视频)
위 내용은 JS 시리즈(3)의 가비지 수집 메커니즘, 메모리 누수, 클로저를 종이 한 장으로 이해하기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!