Nodejs内存控制详解(上篇)

简介: JavaScript与Java一样,由垃圾回收机制来进行自动的内存管理。对于性能敏感的服务器端程序,内存管理的好坏、垃圾回收状况是否优良,都会对服务构成影响。而在Node中,这一切与V8引擎息息相关。

输入图片说明

1 V8的垃圾回收机制与内存限制

JavaScript与Java一样,由垃圾回收机制来进行自动的内存管理。对于性能敏感的服务器端程序,内存管理的好坏、垃圾回收状况是否优良,都会对服务构成影响。而在Node中,这一切与V8引擎息息相关。

1.2 V8的内存限制

Node中通过JavaScript只能使用部分内存(64位约1.4G,32位约0.7G)。V8对内存做了限制。因此这种限制下,将会导致Node无法直接操作大内存对象。

1.3 V8的对象分配

V8中,所有的JavaScript对象都是通过堆来分配的。

可以使用以下命令查看Node中V8内存的使用量。


> $ node
> process.memoryUsage();
{ rss: 25939968,
  heapTotal: 5767168,//已申请到的堆内存
  heapUsed: 4707312,//当前使用的量
  external: 8671 }

至于rss为何物,我们会在下面介绍。

V8的堆示意图:

image

限制内存原因:

  • 首先V8是为浏览器而设计的;前期足以满足网页端的需求;
  • 深层原因是V8的垃圾回收机制,垃圾回收耗时,引起JavaScript线程暂停执行时间。
  • 可以手工调整内存大小


node --max-old-space-size=1700 test.js  //单位为MB。设置老生代

node --max-new-space-size=1024 test.js //单位为KB。设置新生代

1.4 V8的垃圾回收机制

主要的垃圾回收策略是基于分代式的垃圾回收机制:将对象的存活时间进行不同的分代

V8中,主要将内存分为新生代和老生代。新生代中的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。

image

  • 前面讲到的命令是可以分别设置新生代和老生代的大小。

  • 新生代和老生代的最大值需要在启动时就指定,因此无法动态 扩展。手工设置新生代或老生代的内存,只能在启动时就指定,无法动态的扩展。

Scavenge算法

在分代的基础上,新生代中的对象主要通过Scavenge算法进行垃圾回收。Scavenge算法的具体实现中采用了Cheney算法。

  • Cheney算法主要使用了复制的方式实现。

image

  • 新生代堆内存被一分为二
  • From区存放处于使用状态对象
  • TO区为闲置空间
  • 分配对象时首先在From分配
  • 垃圾回收时,检查From空间中的存活对象,将这些对象复制到TO空间。非存活对象直接释放对应空间。
  • 垃圾回收实际上就是将对象在FROMTO两个空间之间复制。
  • 多次复制仍然存活的对象,即生命周期较长的对象,会被移动到老生代。
  • 对象从新生代到老生代的过程称为晋升
  • 对象晋升过程:

image

另一个判断条件是:TO空间使用是否超过25%。如果超过,直接移动到老生代。

设置25%这个值,是因为当Scavenge完成回收后,这个TO区将变成From区,后面的对象分配要在这个区中进行。如果占比过高,会影响后续的内存分配。

Scavenge的缺点是只能使用堆内存的一半。所以无法大规模的运用到所有的垃圾回收中。但是时间效率上有优异的表现。因此非常适合新生代的垃圾回收,因为新生代中的对象存活周期都较短。

Mark-Sweep & Mark-Compact算法

老生代中主要采用这两种算法进行垃圾回收。

因为老生代中的存活对象占比较大,因此使用Scavenge算法会有弊端:

  • 存活对象多,复制效率低;
  • 浪费一半空间;

1.Mark-Sweep:标记清除

分为标记、清除两个阶段;

  • 标记阶段会遍历堆中的所有对象,并只标记活着的对象;
  • 清除阶段只清除没有被标记的对象;

Mark-Sweep | Scavenge

--- | ---

只清理死亡对象 | 只复制存活对象

死对象在老生代中比重小 | 活对象在新生代中比重小

Mark-Sweep的最大问题即是:在清理完后,内存会出现不连续的状态。导致后续对内存的分配可能出现问题,如无法分配一个大对象。

2.Mark-Compact:标记整理

为了解决Mark-Sweep的问题。Mark-Compact在标记对象死亡后,在整理过程中,将活着的对象往一端移动,移动完成后,直接清理掉边界外的内存。

算法比较

| 算法 | Mark-Sweep | Mark-Compact | Scavenge

---| --- | -- |--

速度 | 中等| 最慢 | 最快

空间开销 | 少(有碎片)|少(无碎片)| 双倍空间(无碎片)

是否移动对象 | 否 | 是 | 是

V8主要使用Mark-Compact,在空间不足以对从新生代中晋升过来的对象进行分配时才使用Mark-Sweep。

原文发布时间为:2018年01月20日
原文作者:sunangie 

本文来源:开源中国 如需转载请联系原作者







目录
相关文章
|
7月前
|
存储 Kubernetes 容器
【CKA模拟题】查找集群中使用内存最高的node节点
【CKA模拟题】查找集群中使用内存最高的node节点
69 1
|
27天前
|
监控 JavaScript 算法
如何使用内存监控工具来定位和解决Node.js应用中的性能问题?
总之,利用内存监控工具结合代码分析和业务理解,能够逐步定位和解决 Node.js 应用中的性能问题,提高应用的运行效率和稳定性。需要耐心和细致地进行排查和优化,不断提升应用的性能表现。
180 77
|
27天前
|
监控 JavaScript
选择适合自己的Node.js内存监控工具
选择合适的内存监控工具是优化 Node.js 应用内存使用的重要一步,它可以帮助你更好地了解内存状况,及时发现问题并采取措施,提高应用的性能和稳定性。
115 76
|
27天前
|
监控 JavaScript 数据库连接
解读Node.js内存监控工具生成的报告
需要注意的是,不同的内存监控工具可能会有不同的报告格式和内容,具体的解读方法可能会有所差异。因此,在使用具体工具时,还需要参考其相关的文档和说明,以更好地理解和利用报告中的信息。通过深入解读内存监控报告,我们可以不断优化 Node.js 应用的内存使用,提高其性能和稳定性。
100 74
|
29天前
|
Web App开发 缓存 监控
如何解决Node框架中内存管理的挑战?
解决 Node 框架中内存管理的挑战需要综合运用多种方法,并且需要在开发过程中保持谨慎和细心,不断优化和改进代码。同时,定期进行内存管理的检查和维护也是非常重要的。
110 63
|
29天前
|
存储 缓存 JavaScript
如何优化Node.js应用的内存使用以提高性能?
通过以上多种方法的综合运用,可以有效地优化 Node.js 应用的内存使用,提高性能,提升用户体验。同时,不断关注内存管理的最新技术和最佳实践,持续改进应用的性能表现。
117 62
|
29天前
|
监控 JavaScript Java
Node.js中内存泄漏的检测方法
检测内存泄漏需要综合运用多种方法,并结合实际的应用场景和代码特点进行分析。及时发现和解决内存泄漏问题,可以提高应用的稳定性和性能,避免潜在的风险和故障。同时,不断学习和掌握内存管理的知识,也是有效预防内存泄漏的重要途径。
125 52
|
25天前
|
存储 缓存 监控
如何使用内存监控工具来优化 Node.js 应用的性能
需要注意的是,不同的内存监控工具可能具有不同的功能和特点,在使用时需要根据具体工具的要求和操作指南进行正确使用和分析。
66 31
|
25天前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
39 3
|
29天前
|
缓存 监控 JavaScript
避免在Node.js中出现内存泄漏
总之,避免内存泄漏需要在开发过程中保持谨慎和细心,遵循最佳实践,不断优化和改进代码。同时,定期进行内存管理的检查和维护也是非常重要的。通过采取这些措施,可以有效地降低 Node.js 应用中出现内存泄漏的风险,确保应用的稳定和性能。