`
hongtoushizi
  • 浏览: 376522 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

Node.js 调试 GC 以及内存暴涨的分析

阅读更多

转载自: http://blog.eood.cn/node-js_gc

 

最近做的服务器端组件大部分都在使用 Node.js 。因为 Node.js 库管理模式比较先进,并且依托于 Github 的流行,Node.js 开源的库非常多,一般所需要的第三方库都可以找到。虽然这些库有很多明显的 Bug 但是比从零自己开发要快很多。对于服务器端开发,Node.js 还是个不错的选择,不像 Erlang 更接近底层,业务层面的库相对要少很多。



最近写的一个功能在本地开发的时候没有明显问题,但是到真实环境测试的时候发现内存不断增长,并且增长很快,同时 CPU 占用也很高,接近单核心的 100% 。这对于一个大部分都是 IO 操作的进程显然是有问题的。所以尝试分析内存和 CPU 异常的原因。最终发现是因为生产者和消费者速度差异引起的缓冲区暴增。在 MySQL 连接对象的 Queue 中积压了大量的 Query,而不是内存泄漏。

查看 Node.js 进程的 GC log:

node --trace_gc --trace_gc_verbose test.js
61 ms: Scavenge 2.2 (36.0) -> 1.9 (37.0) MB, 1 ms [Runtime::PerformGC].
Memory allocator,   used: 38780928, available: 1496334336
New space,          used:   257976, available:   790600
Old pointers,       used:  1556224, available:        0, waste:        0
Old data space,     used:  1223776, available:     4768, waste:        0
Code space,         used:  1019904, available:        0, waste:        0
Map space,          used:   131072, available:        0, waste:        0
Cell space,         used:    98304, available:        0, waste:        0
Large object space, used:        0, available: 1495269120
      97 ms: Mark-sweep 11.7 (46.1) -> 5.4 (40.7) MB, 10 ms [Runtime::PerformGC] [GC in old space requested].
Memory allocator,   used: 42717184, available: 1492398080
New space,          used:        0, available:  1048576
Old pointers,       used:  1390648, available:   165576, waste:        0
Old data space,     used:  1225920, available:     2624, waste:        0
Code space,         used:   518432, available:   501472, waste:        0
Map space,          used:    60144, available:    70928, waste:        0
Cell space,         used:    23840, available:    74464, waste:        0
Large object space, used:  3935872, available: 1491332864

关于 Node.js 的 GC

Node.js 的 GC 方式为分代 GC (Generational GC)。对象的生命周期由它的大小决定。对象首先进入占用空间很少的 new space (8MB)。大部分对象会很快失效,会频繁而且快速执行 Young GC (scavenging)*直接*回收这些少量内存。假如有些对象在一段时间内不能被回收,则进入 old space (64-128KB chunks of 8KB pages)。这个区域则执行不频繁的 Old GC/Full GC (mark-sweep, compact or not),并且耗时比较长。(Node.js 的 GC 有两类:Young GC: 频繁的小量的回收;Old GC: 长时间存在的数据)

Node.js 最新增量 GC 方式虽然不能降低总的 GC 时间,但是避免了过大的停顿,一般大停顿也限制在了几十 ms 。

为了减少 Full GC 的停顿,可以限制 new space 的大小

--max-new-space-size=1024 (单位为 KB)

 

手动在代码中操作 GC (不推荐)

node --expose-gc test.js

修改 Node.js 默认 heap 大小

node --max-old-space-size=2048 test.js (单位为 MB)

Dump 出 heap 的内容到 Chrome 分析:

安装库

https://github.com/bnoordhuis/node-heapdump

在应用的开始位置添加

var heapdump = require('heapdump');

在进程运行一小段时间后执行:

kill -USR2 <pid>

这时候就会在当前目录下生成 heapdump-xxxxxxx.heapsnapshoot 文件。
将这个文件 Down 下来,打开 Chrome 开发者工具中的 Profiles,将这个文件加载进去,就可以看到当前 Node.js heap 中的内容了。

可以看到有很多 MySQL 的 Query 堆积在处理队列中。内存暴涨的原因应该是 MySQL 的处理速度过慢,而 Query 产生速度过快。
所以解决方式很简单,降低 Query 的产生速度。内存暴涨还会引起 GC 持续执行,占用了大量 CPU 资源。

node-mysql 库中的相关代码,其实应该限制 _queue 的 size,size 过大则抛出异常或者阻塞,就不会将错误扩大。

Protocol.prototype._enqueue = function(sequence) {
  if (!this._validateEnqueue(sequence)) {
    return sequence;
  }

  this._queue.push(sequence);

  var self = this;
  sequence
    .on('error', function(err) {
      self._delegateError(err, sequence);
    })
    .on('packet', function(packet) {
      self._emitPacket(packet);
    })
    .on('end', function() {
      self._dequeue();
    });

  if (this._queue.length === 1) {
    this._parser.resetPacketNumber();
    sequence.start();
  }

  return sequence;
};

在不修改 node-mysql 的情况下,加入生产者和消费者的同步,调整之后,内存不再增长,一直保持在不到 100M 左右,CPU 也降低到 10% 左右。

Node.js 调试工具 node-inspector

安装:

npm install -g node-inspector

启动自己的程序:

node --debug test.js

node --debug-brk test.js (在代码第一行加断点)

启动调试器界面:

node-inspector

打开 http://localhost:8080/debug?port=5858 可以看到执行到第一行的断点。
右边为局部变量和全局变量、调用栈和常见的断点调试按钮,查看程序步进执行情况。并且你可以修改正在执行的代码,比如在关键的位置增加 console.log 打印信息。

Node.js 命令行调试工具

以 DEBUG 模式启动 Node.js 程序,类似于 GDB:

node debug test.js

debug> help
Commands: run (r), cont (c), next (n), step (s), out (o), backtrace (bt), setBreakpoint (sb), clearBreakpoint (cb),
watch, unwatch, watchers, repl, restart, kill, list, scripts, breakOnException, breakpoints, version

Node.js 其他常用命令参数

node --max-stack-size 设置栈大小

node --v8-options 打印 V8 相关命令

node --trace-opt test.js

node --trace-bailout test.js 查找不能被优化的函数,重写

node --trace-deopt test.js 查找不能优化的函数

Node.js 的 Profiling

V8 自带的 prof 功能:

npm install profiler

node --prof test.js

会在当前文件夹下生成 v8.log

安装 v8.log 转换工具

sudo npm install tick -g

在当前目录下执行

node-tick-processor v8.log

可以关注其中 Javascript 各个函数的消耗和 GC 部分

[JavaScript]:
ticks  total  nonlib   name
67   18.7%   20.1%  LazyCompile: *makeF /opt/data/app/test/test.js:6
62   17.3%   18.6%  Function: ~ /opt/data/app/test/test.js:9
42   11.7%   12.6%  Stub: FastNewClosureStub
38   10.6%   11.4%  LazyCompile: * /opt/data/app/test/test.js:1

[GC]:
ticks  total  nonlib   name
27    7.5%

参考以及一些有用的链接

https://bugzilla.mozilla.org/show_bug.cgi?id=634503
http://cs.au.dk/~jmi/VM/GC.pdf
http://lifecs.likai.org/2010/02/how-generational-garbage-collector.html
http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Na.C3.AFve_mark-and-sweep
http://en.wikipedia.org/wiki/Cheney’s_algorithm
https://github.com/bnoordhuis/node-heapdump
http://mrale.ph/blog/2011/12/18/v8-optimization-checklist.html
http://es5.github.com/
http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/
https://hacks.mozilla.org/2013/01/building-a-node-js-server-that-wont-melt-a-node-js-holiday-season-part-5/
https://gist.github.com/2000999
http://www.jiangmiao.org/blog/2247.html
http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/
http://blog.caustik.com/2012/04/11/escape-the-1-4gb-v8-heap-limit-in-node-js/
https://developers.google.com/v8/embed#handles
https://hacks.mozilla.org/2012/11/fully-loaded-node-a-node-js-holiday-season-part-2/
https://code.google.com/p/v8/wiki/V8Profiler

Related articles

分享到:
评论

相关推荐

    Node.js-《Node.js调试指南》

    总之,《Node.js调试指南》涵盖了Node.js开发中的各种调试技术,从基础到高级,从同步到异步,从错误处理到性能分析,全面地指导开发者提升调试技能,从而编写更稳定、更高效的Node.js应用。通过学习和实践这些技巧...

    Node.js英文书籍2015出版共9本(一次下载)

    Full Stack Javascript - Learn Backbone.js, Node.js and MongoDB (APress 2015).epub Learning Node.js for Mobile Application Development (Packt 2015).pdf Microsoft Press Node.js for .NET Developers (2015...

    Node.js(node-v16.15.1-win-x64.zip)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    node.js14.18.3版本下载

    Node.js 是一个开源、跨平台的 JavaScript 运行环境,它允许开发者在服务器端执行 JavaScript 代码。Node.js 使用 V8 引擎,这是 Google 为 Chrome 浏览器开发的高性能 JavaScript 和 WebAssembly 引擎。Node.js 的...

    Node.js开发-Node.js入门.pdf

    Node.js 是一个基于 JavaScript 的服务器端运行平台,允许开发者使用 JavaScript 语言来编写服务器端应用程序。 Node.js 的出现使得 JavaScript 成为服务器端脚本语言。 Node.js 的主要特点是非阻塞 I/O 和事件驱动...

    Node.js(node-v16.15.1-win-x86.zip)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    node.js(v16.16.0) 安装包

    Node.js 是一个开源、跨平台的 JavaScript 运行环境,它让开发者可以在服务器端执行 JavaScript 代码。Node.js 使用了 Google V8 引擎,这个引擎是为 Chrome 浏览器设计的,因此 Node.js 具有高性能和高效性的特点。...

    Node.js-深入理解Node.js核心思想与源码分析

    Node.js,作为一个基于Chrome V8引擎的JavaScript运行环境,自其诞生以来,就以其高效、异步非阻塞I/O以及事件驱动的特性,迅速在Web开发领域崭露头角。本资料将带你深入探索Node.js的核心思想,并剖析其背后的libuv...

    Node.js By Example

    Node.js的核心特性包括单线程事件循环、异步编程、模块系统以及强大的文件系统操作等。在本书中,你将学习如何利用这些特性来开发高效的应用程序。 1. **事件驱动编程**:Node.js采用事件驱动模型,当有I/O操作时,...

    Node.js-Node.jsforMobileApps是用于Android和iOS的完整版Node.js运行时

    标题中的“Node.js-Node.js for Mobile Apps”指的是将Node.js环境移植到移动设备上,使得开发者能够在Android和iOS平台上直接运行Node.js应用程序。这一技术的出现极大地拓展了JavaScript的适用范围,不再局限于Web...

    Node.js 6.x Blueprints(pdf+epub+mobi+code)

    6. **性能优化**:探讨Node.js的性能监控、调试技巧以及优化策略,如异步编程、内存管理等。 7. **部署与维护**:讲解如何将Node.js应用部署到云平台,如Heroku、Docker,以及持续集成和持续部署(CI/CD)的实践。 8...

    Node.js(node-v16.15.1.pkg)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    node.js 安装包 10.16.3-x64

    Node.js 是一个开源、跨平台的JavaScript运行环境,它允许开发者在服务器端执行JavaScript代码,极大地拓宽了JavaScript的应用领域。10.16.3-x64 版本是 Node.js 的一个稳定版本,适用于64位操作系统。下面将详细...

    使用node-inspector调试Node.js

    在Node.js开发中,调试是不可或缺的一环,它有助于我们找出代码中的错误和性能瓶颈。`node-inspector`是一个强大的工具,它允许我们使用Web Inspector(Chrome或Safari浏览器的开发者工具)来调试Node.js应用。这篇...

    node.js win7版本12.8.0

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它允许开发者在服务器端使用 JavaScript 进行编程。Node.js 提供了一个丰富的生态系统,包含了大量的开源库和工具,使得开发网络应用变得更加便捷。在...

    Node.js硬实战 115个核心技巧.pdf

    8. **性能监控与调试**:了解如何使用工具如New Relic、PM2进行性能监控,以及使用Node.js内置的debug模块进行调试。 9. **错误处理**:良好的错误处理是保证程序稳定运行的关键。书中会介绍如何有效地捕获和处理...

    node.js实战 pdf+源码

    11. **源码分析**:书中的源码示例可以帮助读者深入理解Node.js的实践应用,通过实际操作学习和调试代码,提升技能。 12. **最佳实践**:书中可能涵盖Node.js的最佳实践,包括错误处理、性能优化、代码组织、测试...

    Node.js安装包压缩包

    Node.js是一种开源、跨平台的JavaScript运行环境,它允许开发者在服务器端运行JavaScript代码,极大地扩展了JavaScript的应用范围。Node.js基于Chrome V8引擎,因此它具有高性能和高效率的特点。这个压缩包文件包含...

    前端 - node.js 16.12.0

    Node.js 16.12.0 使用了 V8 版本的最新更新,带来了更快的执行速度和更好的内存管理。V8 引擎的升级通常会带来更快的 JavaScript 解释和编译,以及对 ES 新特性的支持,这使得开发者可以编写更高效的代码。 **2. ES...

    Node.js(node-v16.15.1.tar.gz 源码)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

Global site tag (gtag.js) - Google Analytics