javaScript 内存管理机制
大家好,今天分享的主题为 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 老生代的回收过程采用标记清除、标记整理和标记增量结合的方式。一般在进行垃圾回收时会通过标记清除完成垃圾空间的回收,但是当新生代移动到老生代,而老生代内存不够时,则会通过标记整理进行空间优化,并使用增量标记进行效率优化。

标记增量其实是通过对标记操作进行标记的方法,让时间安排变得合理。这句话可能有些绕,简单说就是在垃圾回收时,让标记系统在标记时分出不同的时间段,分别进行标记和执行,让二者的操作间隔开,从而优化时间安排,这会让页面在体感上更为顺畅。
推荐阅读
javaScript 内存管理机制的更多相关文章
- [原创作品]Javascript内存管理机制
如果你也喜欢分享,欢迎加入我们:QQ group:164858883 内存策略:堆内存和栈内存栈内存:在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个 ...
- python的内存管理机制
先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲 (1)垃圾回收 (2)引用计数 (3)内存池机制 一.垃圾回收: python不像C++,Java等语言一样,他们可以不用事先声明变量 ...
- python的内存管理机制(zz)
本文转载自:http://www.cnblogs.com/CBDoctor/p/3781078.html 先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲 (1)垃圾回收 (2)引用计 ...
- 浅谈Linux内存管理机制
经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...
- ARC内存管理机制详解
ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数. ...
- 深入了解C#系列:谈谈C#中垃圾回收与内存管理机制
今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...
- 【Cocos2d-x 3.x】内存管理机制与源码分析
侯捷先生说过这么一句话 : 源码之前,了无秘密. 要了解Cocos2d-x的内存管理机制,就得阅读源码. 接触Cocos2d-x时, Cocos2d-x的最新版本已经到了3.2的时代,在学习Coco ...
- Spark 1.6以后的内存管理机制
Spark 内部管理机制 Spark的内存管理自从1.6开始改变.老的内存管理实现自自staticMemoryManager类,然而现在它被称之为"legacy". " ...
- Java虚拟机内存管理机制
自动内存管理机制 Java虚拟机(JVM)在执行Java程序过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区 ...
随机推荐
- surface重装系统后,屏幕亮度不能调节,显示适配器出现黄色三角、windows hello不能正常使用
surface重装系统后,屏幕亮度不能调节,显示适配器出现黄色三角,windows hello不能正常使用,解决方法是安装驱动精灵,更新硬件驱动重启即可解决
- 前端知识之JavaScript知识
前端之javaScript JavaScript html :展示文档内容的 css:控制文档的显示效果 js:控制文档的交互效果 是脚本语言 一种轻量级的编程语言 可插入html页面的编程代码 js ...
- centOS 7 离线安装 MySQL 5.6 完美安装
centOS 7 离线安装 MySQL 5.6 centOS 7 离线安装 MySQL 5.6 准备环境 1.离线 centOS 7(此处为 centOS 7 最小安装) 2.nginx 安装文件 ( ...
- Spring Boot整合Redis-转载
Spring Boot整合Redis的三中方式的博客: https://wangsong.blog.csdn.net/article/details/103210490 使用spring.cache. ...
- 通过webgoat-xxe、jwt学习Java代码审计
WebGoat-JWT JWT Tokens 01 概念 本课程将介绍如何使用JSON Web Token(JWT)进行身份验证,以及在使用JWT时需要注意的常见陷阱. 目标 教授如何安全地实现令牌的 ...
- java面向对象思想之封装
一.什么是封装 菜鸟教程对封装的解释是"在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装.隐藏起来的方法.".简单来说就 ...
- 【freertos】005-启动调度器分析
前言 本节主要讲解启动调度器. 这些都是与硬件相关,所以会分两条线走:posix和cortex m3. 原文:李柱明博客:https://www.cnblogs.com/lizhuming/p/160 ...
- callbale 和runnable 区别
Callable接口: 1 2 3 public interface Callable<V> { V call() throws Exception; } Runnable接口: ...
- fiber核心(react 16)?
旧: 浏览器渲染引擎单线程, 计算DOM树时锁住整个线程, 所有行为同步发生, 有效率问题, 期间react会一直占用浏览器主线程,如果组件层级比较深,相应的堆栈也会很深,长时间占用浏览器主线程, 任 ...
- Dubbo 集群容错有几种方案?
集群容错方案 说明 Failover Cluster 失败自动切换,自动重试其它服务器(默认) Failfast Cluster 快速失败,立即报错,只发起一次调用 Failsafe Cluster ...