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

简单介绍Node.js的内存分配和垃圾回收

内存分配

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

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

查看内存使用情况:

1
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的抓取内存堆快照的工具。教程: 如何使用Node Profiler

原文:大专栏  Node.js的内存分配和垃圾回收

原文地址:https://www.cnblogs.com/chinatrump/p/11614933.html

时间: 2024-10-08 22:54:03

Node.js的内存分配和垃圾回收的相关文章

jvm 深入理解自动内存分配与垃圾回收

要想了解jvm自动内存分配,首先必须了解jvm的运行时数据区域,否则如何知道在哪里进行自动内存分配,如何进行内存分配,回收哪里的垃圾对象? jvm运行时数据区:程序计数器,虚拟机栈,本地方法栈,方法区,堆 程序计数器:由于程序指令是一条一条顺序执行,一条执行完之后必须知道下一条该执行那条指令,那么程序计数器就是来记录下一条指令的地址,如果调用本地方法,则程序计数器记录空值,还有由于java线程由cpu调度并发执行,所以程序计数器也有助于线程状态的恢复,程序计数器如果线程共享,在频繁的线程调度下保

Java内存分配与垃圾回收

1.JVM管理的内存包含下图所示的几个运行时数据区域,其中方法区和堆为线程共享的数据区域,程序计数器,虚拟机栈以及本地方法栈为线程私有的数据区域. 程序计数器:可以看做是当前线程所执行的字节码的行号指示器,告诉字节码解释器该读取哪条指令 虚拟机栈:生命周期和线程相同,每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,每一个方法从调用到完成的过程就对应了一个栈帧在虚拟机中入栈到出栈的过程.栈中存放了编译器可知的各种基本数据类型和对象引用. 本地方法栈:与

Java中的内存分配与垃圾回收

一.内存分配 Java程序运行时的内存分配,按照JVM规范,包括以下几个区域:程序计数器.虚拟机栈.本地方法栈.方法区.堆.其中,前三个是线程私有的,与线程生命周期相同,线程退出内存自动回收:后两者是所有线程共享内存的,只在垃圾回收机制被触发时,被动回收. * 程序计数器,内存区域极小,是当前线程的字节码执行行号指示器: * 虚拟机栈.本地方法栈,即平时所说的“栈”,是虚拟机用来执行方法(包括Java.非Java方法)时,使用的临时内存空间,用来存储当前方法.局部变量等,全部基本类型变量,以及类

Java 内存分配及垃圾回收机制初探

一.运行时内存分配 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁. 线程私有区域(生命周期与线程相同) a)  虚拟机栈 虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame[1])用于存储局部变量表. 操作数栈. 动态链接. 方法出口等信息. 每一个方法从调用直至执行完成的

JVM学习之内存分配和垃圾回收

阅读书籍:Java虚拟机精讲(仅个人阅读后总结) 根据受访权限可分为:线程共享内存区和线程私有区 线程共享区: 1.java堆区:储存对象实例: 2.方法区:储存 运行时常量池.字段和数据.构造函数和普通方法的字节码内容以及类.实例.接口初始化需要用到的特殊方法等数据: 3.运行时常量池: 线程私有内存区: 1.PC寄存器:如果当前线程所执行的方法是一个java方法,那么PC寄存器就会存储正在执行的字节码指令地址,反之如果是native方法,这是PC寄存器的值为空(undefined): 2.j

node.js之内存机制特性

Node.JS的V8引擎具有垃圾回收机制与内存限制的特性,V8的内存限制:64位系统约为1.4GB.32位系统约为0.7GB:V8采用基于分代式垃圾回收机制,堆内存结构分为新生代和老生代,新生代达到一定的条件就可以晋升为老生代.如下图所示: 图一  Node.JS堆内存结构 Node.JS能够高效利用内存,它在JavaScript中作用域分为:函数作用域.with作用域.全局作用域.标示符查找会先从当前作用域,若没有找到将会向上级的作用域里查找.查看进程内存使用情况:process.memory

Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收

很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确实很低,一方面,Java语言采用面向对象思想,这也决定了其必然是开发效率高,执行效率低.另一方面,Java语言对程序员做了一个美好的承诺:程序员无需去管理内存,因为JVM有垃圾回收(GC),会去自动进行垃圾回收. 其实不然: 1.垃圾回收并不会按照程序员的要求,随时进行GC. 2.垃圾回收并不会及时

JVM内存管理及垃圾回收

一.JVM内存的构 Java虚拟机会将内存分为几个不同的管理区,这些区域各自有各自的用途,根据不同的特点,承担不同的任务以及在垃圾回收时运用不同的算法.总体分为下面几个部分: 程序计数器(Program Counter Register).JVM虚拟机栈(JVM Stacks).本地方法栈(Native Method Stacks).堆(Heap).方法区(Method Area) 如下图: 1.程序计数器(Program Counter Register) 这 是一块比较小的内存,不在Ram上

JAVA当中内存管理与垃圾回收!

很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确实很低,一方面,Java语言采用面向对象思想,这也决定了其必然是开发效率高,执行效率低.另一方面,Java语言对程序员做了一个美好的承诺:程序员无需去管理内存,因为JVM有垃圾回收(GC),会去自动进行垃圾回收. 其实不然: 1.垃圾回收并不会按照程序员的要求,随时进行GC. 2.垃圾回收并不会及时