Javascript和Java一样,都是通过垃圾回收机制自动对内存进行管理,不像c/c++程序员那样在代码编写时还要考虑内存的分配与释放问题。
Node极大地拓宽了Javascript的应用场景,主流场景从客户端延伸到服务器端之后,对于性能敏感的服务端程序,内存管理的好坏,垃圾回收的状况是否优良,都会对服务构成影响。在Node中,这一切都与Javascript执行引擎V8息息相关。
5.1.1 Node与V8
Node是一个构建在Chrome的Javascript运行时上的平台。Node的创始人选择V8作为Node的Javascript引擎,主要考虑到Chrome优异的性能表现。Chrome的优异表现离不开Javascript引擎V8。V8的性能优势使得用Javascript编写高性能后台服务程序成为可能。
V8的高性能离不开它背后的天才----Lars Bak。Lars Bak曾经在Sun工作,主要从事高性能的Java虚拟机开发工作,他也为Self,Smalltalk语言开发过高性能虚拟机。所以V8一出世就超越了当时所有的Javascript虚拟机。
Node在Javascript的执行上直接受益于V8,同时也受到V8的一些限制,尤其是本文重点讨论的内存限制。
5.1.2 V8的内存限制
在一般的后端开发语言中,基本的内存使用上没有什么限制。然而在Node中通过Javascript使用内存时就会发现只能使用部分内存。这样的限制下,Node无法在内存里操作大内存对象。从而导致在单进程下,计算机内存无法得到充足的使用。
造成这样的问题主要在于Node基于V8构建,V8的内存管理机制在浏览器的应用场景下使用起来绰绰有余,但在Node中,这却限制了开发者使用大内存的限制。
有了这限制,会导致在使用大内存时,如果触发V8内存上限,会导致进程退出。
5.1.3 V8的对象分配
V8中,所有的Javascript对象都是通过堆来进行分配的。Node提供了V8中内存使用量的查看方式,执行下面的代码,将得到输出的内存信息:
$ node
> process.memoryUsage();
{
rss: 14958592,
heapTotal: 7195904,
heapUsed: 2821496
}
其中heapTotal是已经申请到的堆内存,heapUsed是当前使用的量。至于rss,后续会提到。
V8为何会限制堆的大小呢,这是因为V8的垃圾回收机制的限制。以1.5G的垃圾回收堆内存为例,V8做一次小的垃圾回收需要50毫秒以上,做一次非增量式的垃圾回收甚至要1秒以上。这样的时间花销下,应用的性能和响应能力都会直线下降。因此,在这样的情况下,限制内存是一个好的选择。
当然,V8提供了选项让我们使用更多的内存。Node在启动时可以传递–max-old-space-size或–max-new-space-size来调整内存限制的大小。
node --max-old-space-size=1700 test.js // 单位为MB
// 或者
node --max-new-space-size=1024 test.js // 单位为KB
接下来深入地了解V8在垃圾回收方面的策略。
5.1.4 V8的垃圾回收机制
1)V8的内存分代
在V8中,主要将内存分为新生代和老生代两代。新生代的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。
默认情况下,V8堆内存的