大家好,今天分享的主题为 JavaScript 内存管理机制,本次分享将从以下三部分进行讲述:

  • js 内存管理与 js 垃圾

  • 常见的 GC 算法

  • V8 引擎的垃圾回收

js 内存管理与 js 垃圾

关于 JavaScript 内存管理机制,相信大家都有所了解。我们就简单看一下 js 内存管理与 js 垃圾。JavaScript 内存管理是由 JS 自动操作的,不需要人为进行参与,这些内存管理包含以下三项:

  • 申请内存空间

  • 使用内容空间

  • 释放内容空间

而 js 垃圾是指对象不在引用时、对象不能从根上访问到时,都可以被称为 js 垃圾。其他部分包括引用和可达对象这些大家肯定很熟悉了,我们就不再多说。下面我们谈一谈 GC 算法。

GC 算法

GC 算法其实是为了找到内存中的垃圾,并释放和回收空间。这里所说的的垃圾,是指算法中认为程序中不再需要使用的对象,与程序中不能访问到的对象。

说回 GC 算法,这个是比较概念性的内容,我们简单归纳一下。GC 是一种自内存中查找垃圾释放空间、回收空间的一个垃圾回收器机制。算法则是工作时查找和回收所遵循的规则。常见 GC 算法有引用计数、标记清除、标记整理、分代回收。

引用计数

引用计数曾经主要用于 IE8 以下的浏览器,现在的浏览器已不再使用,因此只做简单介绍。引用计数的基本原理是记录跟踪每一个值被引用的次数,被引用则计数加一,被释放则减一,当数值为零时则代表该值所在内存已经不再使用,因此释放所占空间。引用计数的优点是引用次数实时监控,所以回收垃圾能够及时回收,从而最大限度减少程序暂停卡顿时间。但也是因为一直在运作,所以资源消耗和时间开销大,无法回收循环引用的对象。

标记清除

标记清除分为分为标记和清除两个阶段,其核心思想是遍历所有对象,找标记活动对象,即前面提到的可达对象,清除没有标记的对象,以及回收没有标记对象的空间。

上图是 global 的查找简易流程图。其中左侧 A、B、C、D、E 表示可查到的对象,右侧 a1、b1 表示循环引用对象。其中 a1 为引用计数,而因为引用计数一直在运作,无法回收循环引用的对象的缺点,可以反向找到正在循环引用的对象。

这也是标记清除的优点,可以解决对象循环的引用回收问题。但是标记清除的缺点是空间碎片化,无法及时回收垃圾对象。因为它需要先标记再清除,不能像引用计数一样对值进行实时监控,因此无法让空间最大化使用。通过下图可以简单看一下标记清除的空间碎片化特点。

标记整理

上面提到标记清除有空间碎片化的缺点,而标记整理优化了这个缺点。从名字也可以联想到,标记整理是标记清除的增强。标记整理在标记阶段的操作和标记清除一致,但是在清除阶段会先执行整理,再进行清除。这种方式能够有效减少碎片化空间。和标记清除一样,标记整理也不能实时回收垃圾对象。

我们通过下面三张图对标记整理进行一个简单直观的了解。

可以看到在进行垃圾回收前,活动空间和非活动空间是混杂的。而在确定进行回收后,标记整理会对空间进行归类整理,将活动空间和非活动空间统一整理到一起,形成下图的结果:

之后再进行标记清除就能够避免回收操作避免出现大量碎片化空间,让空间最大化应用。

看完了 GC 算法,以 V8 引擎为例我们具体来看一下 GC 算法在 JS 垃圾回收里的使用。

V8 引擎的垃圾回收

V8 是一款当下较为主流 JavaScript 执行引擎,采用即时编译,处理速度很快。V8 的内存是设限的,比如 64 位操作系统的上限是 1.4T,下限是 700M,32 位操作系统的上下限分别为 64M 和 32M。

V8 采用分代回收的垃圾回收策略,将内存分为新生代和旧生代两种,并对不同的对象采用不同的对应算法。

上图是 V8 的内存分配示意图,可以清除看到 V8 内存空间分为两部分。左边的 from 和 to 是新生代,占用的空间比较小(32M|16M),这里的新生代指的是存活时间短的存储区。右边红色的部分则是存活时间较长的老生代存储区。

V8 常用的 GC 算法有以下 5 种:

  • 分代回收

  • 空间复制

  • 标记清除

  • 标记整理

  • 标记增量

这其中新生代采用复制算法和标记整理进行垃圾回收,老生代使用标记清除、标记整理和增量标记进行垃圾回收。

V8 新生代对象回收实现

上图为 V8 新生代对象回收实现图,采用复制算法和标记整理结合的方式进行垃圾回收。新生代内存区的两个等大空间,From 代表使用空间用于存储活动对象,To 代表空闲空间。V8 的新生代对象回收是通过标记整理将对象完成整理后拷贝到 To,然后将 To 和 From 进行空间交换,并释放整理后的无用对象所占空间。需要注意的是,在将整理对象拷贝到 To 时可能会出现晋升。晋升指的是将新生代对象移动至老生代存储区。晋升通常有两个条件,其一是在进行一轮 GC 后还活着的新生代对象可以晋升,其二是 To 空间的使用率超过 25%。

V8 老生代对象回收实现

V8 老生代的回收过程采用标记清除、标记整理和标记增量结合的方式。一般在进行垃圾回收时会通过标记清除完成垃圾空间的回收,但是当新生代移动到老生代,而老生代内存不够时,则会通过标记整理进行空间优化,并使用增量标记进行效率优化。

标记增量其实是通过对标记操作进行标记的方法,让时间安排变得合理。这句话可能有些绕,简单说就是在垃圾回收时,让标记系统在标记时分出不同的时间段,分别进行标记和执行,让二者的操作间隔开,从而优化时间安排,这会让页面在体感上更为顺畅。

推荐阅读

OpenShift 与 OpenStack:让云变得更简单

如何处理大体积 XLSX/CSV/TXT 文件?

javaScript 内存管理机制的更多相关文章

  1. [原创作品]Javascript内存管理机制

    如果你也喜欢分享,欢迎加入我们:QQ group:164858883 内存策略:堆内存和栈内存栈内存:在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个 ...

  2. python的内存管理机制

    先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲 (1)垃圾回收 (2)引用计数 (3)内存池机制 一.垃圾回收: python不像C++,Java等语言一样,他们可以不用事先声明变量 ...

  3. python的内存管理机制(zz)

    本文转载自:http://www.cnblogs.com/CBDoctor/p/3781078.html 先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲 (1)垃圾回收 (2)引用计 ...

  4. 浅谈Linux内存管理机制

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...

  5. ARC内存管理机制详解

    ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数. ...

  6. 深入了解C#系列:谈谈C#中垃圾回收与内存管理机制

    今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...

  7. 【Cocos2d-x 3.x】内存管理机制与源码分析

    侯捷先生说过这么一句话 :  源码之前,了无秘密. 要了解Cocos2d-x的内存管理机制,就得阅读源码. 接触Cocos2d-x时, Cocos2d-x的最新版本已经到了3.2的时代,在学习Coco ...

  8. Spark 1.6以后的内存管理机制

     Spark 内部管理机制 Spark的内存管理自从1.6开始改变.老的内存管理实现自自staticMemoryManager类,然而现在它被称之为"legacy". " ...

  9. Java虚拟机内存管理机制

    自动内存管理机制 Java虚拟机(JVM)在执行Java程序过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区 ...

随机推荐

  1. Monkey的参数及简单使用

    什么是Monkey? Monkey是Android SDK提供的一个命令行工具,可以简单方便的发送伪随机的用户事件流,对Android APP做压力(稳定性)测试.主要是为了测试app是否存在无响应和 ...

  2. windows server 2008r2 在vmware里自动关机

    虚拟机没有激活所以导致自动关机,试试激活它.<wiz_tmp_tag id="wiz-table-range-border" contenteditable="fa ...

  3. 如何做一个网站 (C# + MVC Web+ easyUI )

    如何做一个网站 小编想做一个网站,采用技术为:C# + MVC Web+ easyUI 小编经过几天的学习,以及指了几位大神指导,初见效果.建立网站的思路:先列举需要用到了几个知识点,然后逐一攻克,然 ...

  4. Poco实体

    在Poco实体中,一般只有属性没有方法,这在软件设计中称为贫血模型, 在DDD领域驱动设计中,提倡充血模型,即你的Poco实体中,即有属性,也有操作属性的方法,[PS:注意这里说的是操作属性的方法,你 ...

  5. 关于.NET 6.0 Crossgen2的一些研究

    NET 6.0引入了Crossgen工具的后续版本Crossgen2,这个工具提供了程序提前(AOT)编译的能力. 什么是CrossGen? 我们日常开发时使用C#编译器CSC编译一个.NET程序集, ...

  6. python-binasscii模块学习

    作用 binascii模块包含很多在二进制和ASCII编码的二进制表示转换的方法.通常情况不会直接使用这些功能,而是使用像UU,base64编码,或BinHex封装模块. binascii模块包含更高 ...

  7. Git常见错误整理

    参考文章 git 排错 fatal: 'git status --porcelain' failed in submodule abi/cpp 1 fatal: 'git status --porce ...

  8. @Transactional注解的失效场景

    一口气说出 6种,@Transactional注解的失效场景 计算机java编程 发布时间: 20-03-1912:35优质科技领域创作者 引言 昨天公众号粉丝咨询了一个问题,说自己之前面试被问@Tr ...

  9. 去掉一个Vector集合中重复的元素 ?

    Vector newVector = new Vector(); For (int i=0;i<vector.size();i++) { Object obj = vector.get(i); ...

  10. 简述synchronized和java.util.concurrent.locks.Lock的异同 ?

    主要相同点:Lock能完成synchronized所实现的所有功能 主要不同点:Lock有比synchronized更精确的线程语义和更好的性能.synchronized会自动释放锁,而Lock一定要 ...