一文搞懂JavaScript垃圾回收机制
Posted 工程师-小白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文搞懂JavaScript垃圾回收机制相关的知识,希望对你有一定的参考价值。
一文搞懂javascript垃圾回收机制(GC)
在这之前首先应该搞明白堆和栈的知识
堆和栈
- 栈:JavaScript中的基本数据类型都是存在栈中的,他 的地址是固定的,并且是连续的,后进先出。由系统空间自动分配和释放,相对于堆来说,更容易管理内存空间
- 堆:JavaScript中的引用数据类型都是存在堆中的,虽然说是存放在堆中,但是他们的地址是存储在栈中的,需要从栈中先获得对象的地址指针,然后通过地址来找到堆中的数据,堆是动态分配内存,内存大小不一,地址也不是连续的。
垃圾回收
垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。(说白了就是,内存空间不够了,但是没有别的人用你,我就把你回收了)
发生地点: 堆内存中,因为回收的主要是对象,而对象都是存放在堆内存中
发生时间: 程序空闲时间内,不定时回收
JavaScript的垃圾回收机制:首先需要程序自动的判断这个对象是否可以被回收,如果可以被回收了就标记一下,然后等到下一次执行垃圾回收的时候把有标记的对象全部清除
确定内存需要被回收的方法
方法一: 引用计数:就是给对象加上一个计数器,当用到这个对象的时候加1,用完了之后-1,最终回收计数为0的对象
方法二: 可达性分析:jvm在做垃圾回收的时候。首先需要找出来所有可能作为GCRoot的对象,然后就会顺着这些根元素顺藤摸瓜的向下找,找到的对象就标记为正在使用的对象,没有找到的对象就是没用在用的对象,就可以进行回收了。**(现在基本都是采用这种方法)**可作为 GC Root 的对象包括以下几种:(GCROOT就是找到老大哥,这个老大哥可以用一部分小弟,小弟还可以用到小小弟,一直到最后都没有人用到的小弟,就可以被作为回收对象进行标记)
- 虚拟机栈中正在引用的对象
- 本地方法栈用正在引用的对象
- 静态属性引用的对象
- 方法区常量引用的对象
确定内存被回收后,需要用的垃圾回收算法
- 标记清楚算法: 先识别出所有需要回收的算法,然后进行清除 **缺点:**回收之后会产生大量的不连续的内存碎片,如果在后期运行过程中,需要用到连续的内存空间,就不会使用这些空间,早程内存浪费
- 复制算法: 将内存空间分为两份,每次只使用其中一份,当满了之后把有效的空间(就是活着的对象)放到另一块内存区域中,
优点: 可以避免内存不连续,得到的内存空间都是连续的,
缺点: 就是会浪费一半的内存空间。 - 标记-整理算法: 标记过程与标记-清除算法一样,标记完成之后,将存货的对象向一端移动,确保移动后的对象占用连续的内存空间然后直接清理调边界以外的内存。
优点: 不会产生内存碎片,
缺点: 整理阶段存在效率问题,适合老年代这种垃圾回收频率不是很高的场景 - 分代收集算法
根据对象的存货周期,将划分为几个区域,不同区域采用合适的垃圾收集算法。
新生代: 主要是用来存放新生的对象。一般占据堆空间的1/3,由于频繁创建对象,所以新生代会频繁触发垃圾回收。
新生代分为Eden区、ServivorFrom、ServivorTo三个区
新生代理解: 目的是回收那些生命周期短的对象,主要存放新产生的对象。新生代按照8:1:1分为eden区、survivor0、survivor1,大部分对象在eden区中生成,当eden满时,将存活的对象复制到survivor0,然后清空eden,当eden、survivor0都满了时,将这两个区中存活的对象复制到survivor1,然后清空eden、survivor0,当着三个区都满了时则把存货对象复制到老年代,如果老年代也满了则触发FullGC。新生代的全回收叫MinorGC,MinorGC发生频率比较高,不一定等到新生代满了时才进行。
(说白了就是 新生代给分为三个去 大哥 二哥和三弟,有钱(对象)了 先可着大哥来,大哥装不下了,又发钱了,大哥先把看看兜里面的钱,旧的 褶皱的不能花了就扔掉(把垃圾对象清除),然后把其余的钱都给二哥和三弟,自己再去拿新给的钱)
老年代: 老年代的对象比较稳定,所以MinorGC(就是垃圾回收)不会频繁执行。
新生代使用的是复制算法而老年代使用的是标记整理算法
以上是关于一文搞懂JavaScript垃圾回收机制的主要内容,如果未能解决你的问题,请参考以下文章