【JS】javaScript垃圾回收机制

128 阅读3分钟

1、内存分配场景

JavaScript中主要是根据数据类型区分,主要有以下的七种数据类型,几乎涵盖所有运用场景。

  • 简单数据类型
  • 基本包装类型
  • 对象类型
  • 数组类型
  • 函数类型
  • 其他常用对象
  • 闭包
闭包的定义:函数内部的函数,并且内部函数可以访问外部函数的变量。闭包的主要作用是进行代码隔离。

2、内存回收规则

  • 全局变量:当页面被关闭,内存才会被回收
  • 局部变量:当函数执行完,内存才会被回收
  • 闭包:局部变量的特殊情况,局部变量会被内部函数所占用(引用),就算外部函数执行完成,也不一定会被回收。

3、垃圾回收机制GC的原理及性能优化

标记清除

在变量声明时标记为【进入环境】,当变量使用完成时,标记为【离开环境】,【离开环境】标记的变量将等待被回收。

全局变量在声明时标记为【进入环境】,直到页面关闭时,才标记为【离开环境】,因此,全局变量只有在页面关闭时才会回收;局部变量在函数内部定义时,标记为【进入环境】,在函数执行结束后,就标记为【离开环境】,因此,在函数执行结束后,局部变量就等待被回收。

标记清除的缺点:某些对象被清理后,内存是不连续的。那么就算内存占用率不高,只有50%,但是由于内存空隙太多,后来的大对象无法存储到内存之中。

标记清除缺点的解决方案:在垃圾回收后进行整理操作,这种操作叫做标记整理。就是将不连续的内存向一端复制,使不连续的内存连续起来。

引用计数

跟踪记录每个值被引用的次数。当值的引用次数变为0,说明没有办法再访问这个值,因而可以将其占用的空间回收。当垃圾回收器下次运行时,就会释放那些引用次数为0的值所占用的空间。

主要缺点:存在循环引用的情况,此种情况下,不存在引用次数为0的情况。

解决方案:将引用计数策略换成标记清除策略。

解除引用

一旦数据不再有用,最好通过将其值置为null来释放引用,这一做法适用于大多数的全局变量和局部对象的属性,局部变量会在它们离开执行环境时自动解除引用。

解除一个值的引用并不意味着自动回收该值所占用的内存,解除引用的真正作用是让值脱离执行环境,以便垃圾回收器下次运行时将其回收。

GC的性能优化

引擎需要优化的原因:避免垃圾回收造成的长时间的停止响应。

解决方案:分代回收以及增量回收

分代回收

分代回收是基于以下的假设所设计的

  • 对象越新,生存期越短
  • 对象越老,生存期越长
  • 回收内存的一部分,速度快于回收整个内存

多回收新增对象区,少回收持久对象区,减少每次需要遍历的对象,从而减少垃圾回收的时间。

增量回收

即每次处理一点儿,下次再处理一点儿,分多次回收,以此类推。垃圾回收与应用逻辑交替执行。

增量回收中常采用惰性清理:延迟清理过程,等需要分配内存时再来清理,可进一步提高垃圾回收的效率。

内存的调试技巧

Memory面板及建立快照,对比所使用的内存,可以看到哪个对象所占用内存多导致内存泄漏。