《深入浅出node.js》读书笔记4-1内存控制

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

在Node中,内存管理的好坏、垃圾回收状况是否优良都与JavaScript执行引擎V8息息相关。

V8的内存限制

Node在通过Javascript使用内存时只能使用部分内存(64位系统下约为1.4GB,32位系统下约为0.7GB)。

V8的对象分配

在V8中,所有的Javascript对象都是通过堆来进行分配的

  • Node在启动时可以传递参数来调整内存限制的大小
    1
    2
    node --max-old-space-size=1700 test.js //单位为MB
    node --max-new-space-size=1024 test.js // 单位为KB

V8的垃圾回收机制

  1. V8主要的垃圾回收算法
    V8的垃圾回收策略主要基于分代式垃圾回收机制。
  • 新生代中的对象主要通过Scaverge算法进行回收
  • 老生代中的对象采用Mark-Sweep和Mark-Compact相结合方式进行垃圾回收

查看垃圾回收日志

  • 查看垃圾回收的主要方式是在启动时添加--trace_gc参数。
  • 在启动时使用--prof参数,可以得到V8执行时的性能分析数据。

高效使用内存

V8面前,开发者所要具备的责任是如何让垃圾回收机制更高效地工作。

作用域

在Javascript中能形成作用域的有

  • 函数调用
  • with
  • 全局作用域

闭包

在正常Javascript执行中,无法立即回收的内存有闭包和全局变量引用。需要小心使用。

内存指标

查看内存使用情况

  1. 查看进程的内存占用

调用process.memoryUsage()可以查看Node进程的内存占用情况,示例代码如下:

1
2
3
4
5
6
7
$ node 
process.memoryUsage()
{
res: 13852672,
heapTotal: 6131200,
heapUsed: 2757120
}
  • rss: resident set size, 进程的常驻内存部分,进程的内存除了常驻内存部分还有swap部分、文件系统
  • heapTotal: 堆中总共申请的内存量
  • heapUsed: 堆中使用中的内存量
  1. 查看系统的内存占用
    os模块中的totalmem()freemem(),用于查看操作系统的内存使用情况。
  • totalmem(): 返回系统的总内存
  • freemem(): 返回系统的闲置内存

堆外内存

Node中的内存使用并非都是通过V8进行分配,那些不通过V8分配的内存称为堆外内存
例如Buffer,并且堆外内存可以突破V8内存限制。

小结

Node的内存构成主要由通过V8进行分配的部分和Node自行分配的部分。受V8的垃圾回收限制的主要是V8的堆内存。

内存泄漏

内存泄漏的情况不尽相同,但其实质只有一个:
应当回收的对象出现意外而没有被回收,变成了常驻在老生代中的对象。
通常,造成内存泄漏的原因如下:

  • 缓存
  • 队列消费不及时
  • 作用域未释放

慎将内存当做缓存

Node中,任何试图拿内存当缓存当行为都应当被限制。拿内存当缓存可以理解为在使用全局变量当缓存。

缓存当解决方案

目前较好当解决方案是采用进程外的缓存,进程自身不存储状态。

  1. 缓存转移到外部,减少常驻内存的对象的数量,让垃圾回收更高效
  2. 进程之间可以共享缓存
  3. redis、memcached

关注队列状态

队列同样也会在不经意间产生内存泄漏。
表层解决方案是换用消费速度更高的技术;
深度的解决方案是监控队列的长度;

内存泄漏排查

常用工具:node-heapdump、node-memwatch。
他俩各有所长,可以结合起来使用。

大内存应用

Node提供stream模块用于处理大文件。不受V8堆内存的影响,提供管道方法pipe()

liborn wechat
欢迎您扫一扫上面的微信二维码,订阅我的公众号!