V8 引擎将内存分为新生代和老生代

由于不同对象的生存周期不同,只用一种回收策略来解决问题,这样效率会很低。所以V8采用了一种代回收的策略,将内存分为两个生代:新生代(new generation)和老生代(old generation)。

新生代:新创建的或只经历过一次垃圾回收的对象。

  • 特点:大多数的对象被分配在这里,这个区域很小但是垃圾回特别频繁。

老生代:经历过多次垃圾回收的对象。

  • 特点:所保存的对象大多数是生存周期很长的甚至是常驻内存的对象,而且老生代占用的内存较多。

如何判断是否可以被回收:

  • 标记清除

当函数中声明一个变量时,就将这个变量标记为“进入环境”。而当变量离开环境时,则将其标记为“离开环境”。

首先,垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(可以使用任何标记方式)。

然后,它会去掉运行环境中的变量以及被环境中变量所引用的变量的标记。

此后,依然有标记的变量就被视为准备删除的变量,原因是在运行环境中已经无法访问到这些变量了。

最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

  • 引用计数

引用计数的垃圾收集策略不太常见。含义是跟踪记录每个值被引用的次数。

当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。

如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,改变了引用对象,则该值引用次数减1。

当这个值的引用次数变成0时,则说明没有办法再访问这个值了,在垃圾收集器下次再运行时,它就会释放内存。

垃圾回收算法:

新生代为存活时间较短的对象,老生代为存活时间较长或常驻内存的对象,分别对新老生代采用不同的垃圾回收算法来提高效率。

  • 新生代垃圾回收算法

新生代使用Scavenge算法进行回收。在Scavenge算法的实现中,主要采用了Cheney算法。

Cheney算法算法是一种采用复制的方式实现的垃圾回收算法。新生代的空间被分为To和From空间。To一般是闲置的,对象都被存放在From空间,当From空间满了就会执行Scavenge 算法进行垃圾回收。当开始进行垃圾回收算法时,会检查From空间中的存活对象,这些存活对象将会被复制到To空间中(复制完成后会进行紧缩),而非活跃对象占用的空间将会被释放。完成复制后,From空间和To空间的角色发生对换。也就是说,在垃圾回收的过程中,就是通过将存活对象在两个semispace之间进行复制。可以很容易看出来,使用Cheney算法时,总有一半的内存是空的。但是由于新生代很小,所以浪费的内存空间并不大。而且由于新生代中的对象绝大部分都是非活跃对象,需要复制的活跃对象比例很小,所以其时间效率十分理想。

  • 老生代垃圾回收算法

老生代占用内存较多(64位为1.4GB,32位为700MB),如果使用Scavenge算法,浪费一半空间不说,复制如此大块的内存消耗时间将会相当长。所以Scavenge算法显然不适合。V8在老生代中的垃圾回收策略采用Mark-Sweep和Mark-Compact相结合。

  Mark-Sweep(标记清除)
标记清除分为标记和清除两个阶段。在标记阶段需要遍历堆中的所有对象,并标记那些活着的对象,然后进入清除阶段。在清除阶段总,只清除没有被标记的对象。由于标记清除只清除死亡对象,而死亡对象在老生代中占用的比例很小,所以效率较高。

标记清除有一个问题就是进行一次标记清除后,内存空间往往是不连续的,会出现很多的内存碎片。如果后续需要分配一个需要内存空间较多的对象时,若所有的内存碎片都不够用,将会使得V8无法完成这次分配,提前触发垃圾回收。

  Mark-Compact(标记整理)
标记整理正是为了解决标记清除所带来的内存碎片的问题。标记整理在标记清除的基础进行修改,将其的清除阶段变为紧缩极端。在整理的过程中,将活着的对象向内存区的一段移动,移动完成后直接清理掉边界外的内存。紧缩过程涉及对象的移动,所以效率并不是太好,但是能保证不会生成内存碎片。

在V8的回收策略中,Mark-Sweep和Mark-Conpact两者是结合使用的。主要使用标记清除,在空间不足以对从新生代中晋升过来的对象进行分配时,才使用标记整理。

对象的晋升:

当一个对象满足某些条件,就会被移动到老生代,这称为对象的晋升。具体标准有两种:

判断是对象否已经经过一次 Scavenge 回收。若经历过,则将对象从 From 空间复制到老生代中;若没有经历,则复制到 To 空间。

其次判断To 空间的内存使用占比是否超过限制。当对象从 From 空间复制到 To 空间时,若 To 空间使用超过 25%,对象直接晋升到老生代中。设置 25% 的原因主要是因为两个空间会交换位置,如果 To 空间的内存太小,会影响后续的内存分配。

总结:

V8的垃圾回收机制分为新生代和老生代。

新生代主要使用Scavenge进行管理,将内存平均分为两块,使用的叫From空间,闲置的叫To空间。新对象都先分配到From空间中,回收时先判断是否存活,如果存活将存活对象复制到To空间中,清空From的内存空间后,再调换From空间和To空间,继续进行内存分配。且满足晋升条件时对象会从新生代晋升到老生代。

老生代主要采用Mark-Sweep和Mark-Compact算法,一个是标记清除,一个是标记整理。两者不同的地方是,标记清除在垃圾回收后会产生碎片内存,而标记整理在清除前会进行一步整理,将存活对象向一侧移动,随后清空边界的另一侧内存,这样空闲的内存都是连续的,但速度会慢一些。在V8中,老生代是标记清除和标记管理共同进行管理的。

由于在进行垃圾回收的时候会暂停应用的逻辑,对于新生代方法由于内存小,每次停顿的时间不会太长,但对于老生代来说每次垃圾回收的时间长,停顿会造成很大的影响。为了解决这个问题 V8 引入了增量标记的方法,将一次停顿进行的过程分为了多步,每次执行完一小步就让运行逻辑执行一会,就这样交替运行。

V8 引擎的垃圾回收机制的更多相关文章

  1. 一文搞懂V8引擎的垃圾回收

    引言 作为目前最流行的JavaScript引擎,V8引擎从出现的那一刻起便广泛受到人们的关注,我们知道,JavaScript可以高效地运行在浏览器和Nodejs这两大宿主环境中,也是因为背后有强大的V ...

  2. V8引擎的垃圾回收策略

    V8 的垃圾回收策略主要基于分代式垃圾回收机制.所谓分代式,就是将内存空间分为新生代和老生代两种,然后采用不同的回收算法进行回收. 新生代空间 新生代空间中的对象为存活时间较短的对象,大多数的对象被分 ...

  3. V8 下的垃圾回收机制

    V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制.因此,V8 将内存(堆)分为新生代和老生代两部分. 1.新生代算法 新生代中的对象一般存活时间较短,使用 Scavenge GC 算法. ...

  4. 浅谈Chrome V8引擎中的垃圾回收机制

    垃圾回收器 JavaScript的垃圾回收器 JavaScript使用垃圾回收机制来自动管理内存.垃圾回收是一把双刃剑,其好处是可以大幅简化程序的内存管理代码,降低程序员的负担,减少因 长时间运转而带 ...

  5. 浅谈V8引擎中的垃圾回收机制

    最近在看<深入浅出nodejs>关于V8垃圾回收机制的章节,转自:http://blog.segmentfault.com/skyinlayer/1190000000440270 这篇文章 ...

  6. Chrome V8系列--浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略

    V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制.因此,V8 将内存(堆)分为新生代和老生代两部分. 一.前言 V8的垃圾回收机制:JavaScript使用垃圾回收机制来自动管理内存.垃圾 ...

  7. v8垃圾回收和js垃圾回收机制

    垃圾回收器是一把十足的双刃剑.好处是简化程序的内存管理,内存管理无需程序员来操作,由此也减少了长时间运转的程序的内存泄漏.然而无法预期的停顿,影响了交互体验.本文从 V8 (node.js runti ...

  8. 超详细的node/v8/js垃圾回收机制

    前言 垃圾回收器是一把十足的双刃剑.其好处是可以大幅简化程序的内存管理代码,因为内存管理无需程序员来操作,由此也减少了(但没有根除)长时间运转的程序的内存泄漏.对于某些程序员来说,它甚至能够提升代码的 ...

  9. V8 内存管理和垃圾回收机制总结

    这篇文章主要介绍 V8 的内存管理和垃圾回收知识. V8 内存管理及垃圾回收机制浅析 由于 V8 引擎的原因,Node 在操作大内存对象时受到了一些限制,在 64 位的机器上,默认最大操作的对象大小约 ...

随机推荐

  1. JVM学习十二 - (复习)JVM内存结构

    JVM 内存结构 Java 虚拟机的内存空间分为 5 个部分: 程序计数器 Java 虚拟机栈 本地方法栈 堆 方法区 JDK 1.8 同 JDK 1.7 比,最大的差别就是:元数据区取代了永久代.元 ...

  2. Ajax接收服务器返回的信息response

    Ajax可以向服务器发起请求,有去的方式,那么久必然可疑返回. 服务器返回的信息也可以通过Ajax接收. Ajax共有5种状态: 1.创建对象,没有调用open方法 2.对象发起请求http,已经调用 ...

  3. NSArray 遍历

    1.NSArray的下标遍历 NSArray *arr = @[p1, p2, p3, p4, p5]; for (int i = 0; i < arr.count; ++i) { Person ...

  4. ARC下的内存管理

    1.ARC下单对象内存管理 局部变量释放对象随之被释放 int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = ...

  5. Idea快捷键---根据自己使用情况持续更新

    查看接口的实现类 -->ctrl+alt+b 查看继承关系 -->ctrl+h 快速查看上次查看代码的位置: -->ctrl+alt+方向键(注意与intel显卡快捷键的冲突,如有冲 ...

  6. having筛选结果集

    题目要求:让你输出有两科及其以上挂科(60分及格)的学生的名单? name subject score 错误的做法: mysql> select name, count(scoure<60 ...

  7. Xcode 插件推荐

    1. Alcatraz(建议安装,以下插件都可以在Alcatraz下载安装) 使用Alcatraz来下载管理Xcode插件, 2.下载安装注释插件VVDocumenter-Xcode. 3.使用代码对 ...

  8. 宝塔面板部署springboot项目并使用域名访问

    环境准备:服务器搭建宝塔linux面板项目: springboot项目项目打包方式jar包 环境: 一.服务器,一个域名,然后再服务器上(DNS服务)将域名解析好.把安全组设置好. 二.用宝塔快速搭建 ...

  9. linux13

    ansible-playbook实现MySQL的二进制部署 Ansible playbook实现apache批量部署,并对不同主机提供以各自IP地址为内容的index.html http的报文结构和状 ...

  10. nodejs并行无关联

    var async = require('async'); //串行无关联series//串行有关联waterfall//并行:parallel //会把各个函数的执行结果一起放到最后的回调中asyn ...