大家好,今天分享的主题为 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. Python的安装教程与环境配置

    安装环境:Windows7或者Windows10 Python版本:最新即可,这里选用 python 3.7.2: 一.下载:在python的官网下载python版本,需要下载对应版本(在计算机-属性 ...

  2. SSM(Spring+SpringMVC+MyBatis)框架整合开发流程

    回忆了 Spring.SpringMVC.MyBatis 框架整合,完善一个小demo,包括基本的增删改查功能. 开发环境 IDEA MySQL 5.7 Tomcat 9 Maven 3.2.5 需要 ...

  3. flexible如何实现自动判断dpr?

    判断机型, 找出样本机型去适配. 比如iphone以6为样本, 宽度375px, dpr是2

  4. SQL语句分为哪几种?

    SQL语句主要可以划分为以下几类: DDL(Data Definition Language):数据定义语言,定义对数据库对象(库.表.列.索引)的操作. 包括:CREATE.DROP.ALTER.R ...

  5. 构造器(constructor)是否可被重写(override)?

    构造器不能被继承,因此不能被重写,但可以被重载.

  6. Oracle入门基础(九)一一创建表和管理表

    练习:查询每一年入职人数及总人数 SQL> select count(*) Total, 2 sum(decode(to_char(hiredate,'yyyy'),'1980',1,0)) & ...

  7. ZAB 和 Paxos 算法的联系与区别?

    相同点: 1.两者都存在一个类似于 Leader 进程的角色,由其负责协调多个 Follower 进程的运行 2.Leader 进程都会等待超过半数的 Follower 做出正确的反馈后,才会将一个提 ...

  8. Java 中 LinkedHashMap 和 PriorityQueue 的区别是 什么?

    PriorityQueue 保证最高或者最低优先级的的元素总是在队列头部,但是 LinkedHashMap 维持的顺序是元素插入的顺序.当遍历一个 PriorityQueue 时,没有任何顺序保证,但 ...

  9. 学习Nginx(一)

    实验目的 通过nginx实现反向代理的功能,类似apache反向代理和haproxy反向代理 工作中用nginx做反向代理和负载均衡的也越来越多了 有些公司从web服务器到反向代理,都使用nginx. ...

  10. Netty学习摘记 —— 初步认识Netty核心组件

    本文参考 我在博客内关于"Netty学习摘记"的系列文章主要是对<Netty in action>一书的学习摘记,文章中的代码也大多来自此书的github仓库,加上了一 ...