Node.js的内存分配和垃圾回收

更新日期: 2019-10-01阅读: 2.1k标签: 内存

内存分配

Node.js是一个由JavaScript V8引擎控制的C++程序,V8的内存管理模式一个运行的程序通常是通过在内存中分配一部分空间来表示的。这部分空间被称为驻留集(Resident Set)。
V8的内存管理模式有点类似于Java虚拟机(JVM),它会将内存进行分段:

代码 Code:实际被执行的代码
栈 Stack:包括所有的携带指针引用堆上对象的值类型(原始类型,例如整型和布尔),以及定义程序控制流的指针。
堆 Heap:用于保存引用类型(包括对象、字符串和闭包)的内存段

查看内存使用情况:

console.log(process.memoryUsage());


垃圾回收机制

V8的垃圾回收机制分代式垃圾回收,基于这个机制,V8把内存分为新生代(New Space)和 老生代 (Old Space)。
新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。
–max-old-space-size 命令就是设置老生代内存空间的最大值,而 –max-new-space-size 命令则可以设置新生代内存空间的大小。


垃圾回收算法

在V8中,按对象的存活时间将内存的垃圾回收进行不同的分代,然后分别对不同的内存施以更高效的算法。
新生代中的垃圾回收在新生代中,主要通过 Scavenge 算法进行垃圾回收。


Scavenge

Scavenge算法将堆内存一分为二,每一部分空间称为semispace。在这两个semispace空间中,只有一个处于使用中,另外一个处于闲置状态。
处于使用状态的semispace称为From空间,处于闲置状态的semispace称为To空间。当我们分配对象时,先是从From空间中分配。当开始进行垃圾回收时,
会检查From空间中存活的对象,这些存活的对象会被复制到To空间中,而非存活的对象占用的空间会被释放。完成复制后,From空间和To空间角色互换。
在垃圾回收的过程中,就是通过将存活对象在两个semispace空间之间进行复制。


新生代中的对象怎样到老生代中

在新生代存活周期长的对象会被移动到老生代中,需要符合两个条件中的一个:

  1. 对象是否经历过Scavenge回收。
    对象从From空间中复制到To空间时,会检查它的内存地址来判断这个对象是否已经经历过一次Scavenge回收,如果已经经历过了,则将该对象从From空间中复制到老生代空间中。
  2. To空间的内存占比超过25%限制。
    当对象从From空间复制到To空间时,如果To空间已经使用超过25%,则这个对象直接复制到老生代中。这么做的原因在于这次Scavenge回收完成后,这个To空间会变成From空间,
    接下来的内存分配将在这个空间中进行。如果占比过高,会影响后续的内存分配。

所以,V8在老生代中主要采用「Mark-Sweep」算法与「Mark-Compact」算法相结合的方式进行垃圾回收。
老生代中的垃圾回收对于老生代的对象,由于存活对象占比较大比重,
使用Scavenge算法显然不科学。一来复制的对象太多会导致效率问题,二来需要浪费多一倍的空间。


Mark-Sweep

Mark-Sweep是标记清除的意思,分为标记和清除两个阶段。在标记阶段遍历堆中的所有对象,并标记存活的对象,在随后的清除阶段中,只清除标记之外的对象。
但是Mark-Sweep有一个很严重的问题,就是进行一次标记清除回收之后,内存会变得碎片化。如果需要分配一个大对象,这时候就无法完成分配了。这时候就该Mark-Compact出场了。


Mark-Compact

Mark-Compact是标记整理的意思,是在Mark-Sweep基础上演变而来。Mark-Compact在标记存活对象之后,在整理过程中,将活着的对象往一端移动,移动完成后,直接清理掉边界外的内存。


增量标记(Incremental Marking)

鉴于Node单线程的特性,V8每次垃圾回收的时候,都需要将应用逻辑暂停下来,待执行完垃圾回收后再恢复应用逻辑,被称为全停顿。
在分代垃圾回收中,一次小垃圾回收只收集新生代,且存活对象也相对较少,即使全停顿也没有多大的影响。但是在老生代中,存活对象较多,
垃圾回收的标记、清理、整理都需要长时间的停顿,这样会严重影响到系统的性能。所以增量标记被提出来。它从标记阶段入手,
将原本要一口气停顿完成的动作改为增量标记,拆分为许多小「步进」,每做完一「步进」就让JavaScript应用逻辑执行一小会,
垃圾回收与应用逻辑这样交替执行直到标记阶段完成。


内存泄露排查的工具

node-heapdump:它允许对V8堆内存抓取快照,用于事后分析。

node-profiler:它是alinode团队出品的类似node-heapdump的抓取内存堆快照的工具。


链接: https://www.fly63.com/article/detial/5619

JavaScript 内存管理和垃圾回收

JavaScript 的内存管理和垃圾回收,是个略生僻的话题,因为在JavaScript 中不显式执行内存操作,不过最好了解它如何工作。

js常见的内存泄漏及解决方法总汇

js具有自动回收垃圾的机制,即执行环境会负责管理程序执行中使用的内存。在C和C++等其他语言中,开发者的需要手动跟踪管理内存的使用情况。在编写js代码时候,开发人员不用再关心内存使用的问题,所需内存的分配 以及无用的回收完全实现了自动管理。

浅谈javaScript内存机制

javaScript内存空间并不是一个经常被提及的概念,想要对JS的理解更加深刻,就必须对内存空间有一个清晰的认:栈与堆、复杂数据类型与基本数据类型、引用数据类型与堆内存

js 把一个对象赋值给另一个对象会指向同一个内存地址

实际上并不是新建一个和原对象(数组也是对象)完全一样的对象,而是把原对象的内存地址直接复制给了另一个对象,也就是说两个对象都是指向同一个内存地址,所以实际上它们就是同一个对象。

php底层原理之垃圾回收机制

php垃圾回收机制,对于PHPer来说是一个不陌生但是又不是很熟悉的内容。那么php是怎么实现对不需要的内存进行回收的呢?首先还是需要了解下基础知识,便于垃圾回收原理内容的理解。

js变量、作用域和内存问题

JavaScript变量可以用来保存两种类型的值:基本类性值和引用类性值。所有变量(包括基本类型和引用类型)都存在于一个执行环境(也称为作用域)当中,具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配和回收问题

php中的内存管理

计算机的内存由操作系统进行管理,所以普通应用程序是无法直接对内存进行访问的。应用程序只能向操作系统申请内存,通常的应用也是这么做的,在需要的时候通过类似malloc之类的库函数 向操作系统申请内存。

原生JS与Jquery删除iframe并释放内存-IE

当项目以tab页签方式打开多个iframe窗口时,关闭tab页签同时也需要关闭iframe并释放内存资源,主要是针对IE浏览器。

闭包真的会导致内存泄漏?

今天遇到一个很有争议的问题,在这里分享一下,我相信对于即将面试前端的小伙伴会有帮助的。主要内容是围绕下边的问题展开的,文章涉及到的其他方面的知识点不展开叙述。

Web 应用的内存优化

随着 Web 应用复杂程度越来越高,以及 NodeJS 大规模投入生产环境,许多 Web 应用都会长时间运行, JavaScript 的内存管理显得更为重要。JavaScript 具备自动回收垃圾的机制

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!