大家好,今天分享的主题是内存管理机制。本次分享将分以下三个部分进行介绍:
js内存管理和js垃圾
关于内存管理机制,相信大家都知道一些。下面简单介绍一下js内存管理和js垃圾。内存管理由 JS 自动操作,不需要人工参与。这些内存管理包括以下三项:
js垃圾是指对象未被引用,无法从root访问对象的时间,可以称为js垃圾。其他部分,包括引用和可达对象,大家肯定都很熟悉了,这里就不多说了。现在让我们谈谈GC算法。
GC算法
GC算法其实就是在内存中寻找垃圾,释放和回收空间。这里所说的垃圾是指算法认为程序不再需要使用的对象,以及程序中无法访问的对象。
说起GC算法,这是一个比较概念的内容,所以简单总结一下。GC是一种垃圾收集器机制,它在内存中找到垃圾以释放空间和回收空间。算法是在工作时寻找和回收的规则。常见的 GC 算法包括引用计数、标记清除、标记排序和分代回收。
引用计数
引用计数以前主要用在IE8以下的浏览器中,现在浏览器已经不用了,这里只做简单介绍。引用计数的基本原理是记录和跟踪每个值被引用的次数。被引用时计数加一,释放时减一。当该值为零时,表示该值所在的内存不再被使用,因此占用的空间被释放。. 引用计数的好处是实时监控引用的数量,因此可以及时收集垃圾回收,从而最大限度地减少程序暂停时间。但也正是因为它一直在运行,所以资源消耗和时间开销都很大,循环引用的对象无法恢复。
标记清楚
标记清除分为标记和清除两个阶段。核心思想是遍历所有对象,找到被标记的活动对象,也就是上面提到的可达对象,清除未标记的对象,回收未标记对象的空间。
上图是一个简单的搜索流程图。其中,左边的A、B、C、D、E代表可以找到的对象,右边的a1、b1代表循环引用的对象。其中,a1为引用计数,由于引用计数一直在运行,循环引用对象的缺点无法挽回,可以逆向找到循环引用对象。
这也是mark-sweep的优点,可以解决对象循环的引用回收问题。但是,mark-的缺点是空间碎片化,垃圾对象不能及时回收。因为需要先标记然后清除,不能像引用计数一样实时监控值,所以不能最大限度的利用空间。下图简要介绍了标记删除的空间碎片特征。
标记
如上所述,标记清除存在空间碎片化的缺点,标记排序优化了这个缺点。顾名思义,标记清理是对标记删除的增强。标记阶段标记排序的操作与标记清除相同,但在清除阶段,先进行排序,再进行清除。这种方法可以有效减少碎片空间。与mark-sweep 一样,mark-sweep 不会实时收集垃圾对象。
通过下面三张图,我们对标签排序有了一个简单直观的认识。
可以看出,在垃圾回收之前,活动空间和非活动空间是混合在一起的。确定回收后,标记和排序会对空间进行分类,将活动空间和非活动空间组织在一起,形成下图的结果:
标记清零后,可以避免回收操作,避免大量碎片化空间,最大限度地利用空间。
看完GC算法,以V8引擎为例,我们来看看GC算法在JS垃圾回收中的使用。
V8 引擎的垃圾收集
V8是目前比较主流的执行引擎。采用实时编译,处理速度快。V8 的内存是有限的。比如64位操作系统的上限是1.4T,下限是700M,32位操作系统的上限和下限分别是64M和32M。
V8采用分代回收的垃圾回收策略,将内存分为新生代和老年代两种,针对不同的对象采用不同的对应算法。
上图是V8的内存分配示意图。可以看出V8内存空间分为两部分。左边的from和to是新一代,占用空间比较小(32M|16M)。这里的新生代是指生存时间较短的存储区域。右边红色部分是存活时间较长的老年代存储区。
V8中有五种常用的GC算法:
其中,新生代使用复制算法和标记排序进行垃圾收集,老一代使用标记清除、标记排序和增量标记进行垃圾收集。
V8 新一代对象回收实现
上图是V8新生代对象回收的实现图,它使用复制算法和标签排序相结合的方式进行垃圾回收。新生代内存区域中两个大小相等的空间,From代表存储活动对象的已用空间,To代表空闲空间。V8 的新一代对象回收是通过标记和排序完成排序后将对象复制到 To,然后交换 To 和 From 之间的空间,释放排序后的无用对象占用的空间。请注意,将整理对象复制到 To 时可能会发生提升。提升是指将年轻代对象移动到老年代存储。升职通常有两个条件。一是可以提升经过一轮GC后还活着的新生代对象,
V8老年代对象回收实现
V8老年代的回收过程采用标记清除、标记排序和标记增量相结合的方式。一般垃圾回收时,通过标记和清除的方式回收垃圾空间。但是当新生代移动到老年代,老年代内存不足时,通过标记排序进行空间优化,使用增量标记进行效率优化。
标记增量实际上是标记标记操作以使时间合理的一种方式。这句话可能有点混乱。简单来说就是在垃圾回收的时候,让标记系统在标记的时候划分不同的时间段,分别标记和执行,让两者的操作有间隔,从而优化时间安排,这样会让页面感觉更流畅.
暂无评论内容