nodejs的垃圾回收机制由v8引擎自动管理。nodejs的内存限制一般后端语言(php)来说,对内存的使用是没有限制的,但是对于nodejs来说,只能使用系统的一部分----1.4Gfor64-bit系统,1.4G,32位系统bit0.7G。这时候如果要处理一个3G的文件进行数据分析,即使系统内存8G,nodejs进程中的内存还是会溢出。上面的问题主要是因为nodejs是基于v8的,nodejs是通过v8自己的方式来管理内存的。为什么v8要限制堆内存的大小?有2个原因:1.表面原因:v8是为浏览器设计的,不太可能遇到大内存场景。2.底层原因:v8垃圾回收机制的局限性。以1.5G的堆内存为例,v8做一次小垃圾回收需要50ms,做一次非增量垃圾回收需要1s。垃圾回收会导致js线程被挂起。花费这样的时间,应用程序的性能和响应能力将直线下降。可以开启内存限制:--max-old-space-size(oldgeneration)--max-new-space-size(newgeneration)v8堆内存大小=oldgeneration+newgenerationv8垃圾回收机制v8垃圾回收it主要是基于分代垃圾回收机制。根据对象的存活时间,将内存的垃圾回收分为不同的代,不同代的内存采用不同的算法。新生代--->存活时间较短的对象老年代--->存活时间较长的对象或驻留内存上面说了nodejs堆内存的大小就是新生代的内存空间加上老年代的内存空间。新生代算法新生代主要采用清道夫算法进行垃圾回收。这是一种通过复制实现垃圾回收的方法,将堆内存一分为二,每个空间称为半空间。在这两个半空间中,只有一个在使用中(从空间调用),另一个是空闲的(从空间调用)。开始分配时,首先从from空间开始。当垃圾回收开始时,还从from空间中检查存活的对象,并将存活的对象复制到to空间。非存活对象占用的空间将被释放。复制后,fromspace和tospace的角色互换了。从上面的过程我们可以知道,scavenge的缺点是只使用了一半的堆内存,牺牲了空间获取时间。老年代通过mark-sweep和mark-comopact算法。mark-sweep标记清除分为标记和清除两个阶段。mark-sweep在标记阶段首先遍历堆内存中的所有对象,对存活的对象进行标记;在清除阶段,清除未标记的对象。可以看出,scavenge只复制存活的对象,而mark-sweep只清理死对象。因为新生代中存活的对象所占比例较小,而老年代中的死对象所占比例较小,这就是这两种算法效率高的原因。mark-compact标记整理,mark-sweep会出现问题,回收后会出现内存不连续状态(内存碎片)。内存碎片会影响后续的内存分配,因为会出现这样一种情况:需要分配一块很大的内存,而所有的内存碎片都无法完成分配,就会提前触发垃圾回收,而这种回收是不必要的。Mark-compact是在Mark-sweep的基础上发展而来的。它的主要区别在于对象被标记后,排序过程中会将所有存活的对象移动到一端,移动完成后直接清除。总结:正常使用,v8的内存限制还是够用的,但是nodejs的垃圾回收和单线程还是会影响性能。如果你想要高性能,你需要让垃圾收集尽可能小。在实际开发中,需要使用老年代对象。例如,Web服务的会话(session)一般存储在内存(数组)中。在大量访问的情况下,老年代对象会急剧增加,可能会造成溢出。如果要处理内存较大的数据,比如读取3G文件,我们会使用可读流的pipe()方法,这样就不会受到v8内存限制的影响,提高nodejs程序的健壮性.
