内存控制
v8的垃圾回收机制和内存限制
对于性能敏感的服务器端程序,内存管理的好坏,垃圾回收状态的优良成都,都会对服务器造成影响
Node和V8
Node在JavaScript的执行上受益于v8,随着v8的升级享受到更好的性能和性的语言特征。
V8的内存限制
node无法直接操作大内存对象。在单个node进程情况下,计算机的内存资源无法得到充足的使用
造成这个问题的原因:node基于v8构建,所以node中使用的JavaScript对象都是通过v8自己的方式来分配和管理的。但是限制了开发者使用大内存的想法
V8的对象分配
在JavaScript中,对象是通过堆来进行分配的。node提供了v8中内存使用量查看的方式
$node
> process.memoryUsage()
在上述代码中,memoryUsage()方法的返回属性中。heapTotal
和heapUsed
是v8的堆内存使用情况,前者是已经申请到的堆内存,后者是当前使用的量
v8限制堆大小的原因
- v8为浏览器设计,不太可能遇到大量使用内存的场景。对于页面来说,v8的限制已经搓搓有余。
- v8垃圾回收机制的限制。v8做一次小的垃圾回收需要50ms以上。做一次非增量式的垃圾回收需要1s以上,这是垃圾回收中引起JavaScript线程暂停执行的时间。在这样的时间花销下,应用的性能和响应都会下降。
V8的垃圾回收机制
v8的垃圾回收算法
v8的垃圾回收策略主要是基于分代式垃圾回收机制。`垃圾回收算法按照对象的存活时间将内存中的垃圾回收进行不同的分代,然后分代对于不同的分代的内存施以更加高效的算法`
v8的内存分代
将内存分为新生代和老生代。新生代的对象为存活时间较短的对象,老生代的对象为存活时间较长或者常驻的对象。
V8堆的整体大小就是新生代所用的内存空间加上老生代的内存空间。--max-old-space-size
可以用来设置老生代的内存空间的大小。--max-new-space-size
可以设置新生代内存空间的大小。这两个值在启动的时候就需要指定,v8使用的内存没有办法根据情况自动扩充。对于新生代内存,有两个reserved_semispace_size_
所构成。机器位数不同,reserved_semispace_size在64位系统和32系统上分别为16mb和8mb。 v8堆内存的最大保留空间。4 * reserved_semispace_size + max_old_generation_size_
v8在64位系统下能使用1.4gb,在32位系统下使用0.7gb
Scavenge算法
在分代的基础上,新生代的对象使用scavenge算法进行垃圾回收。在Scavenge的实现中,使用了Cheney算法。是典型的牺牲空间换取时间的算法。所以无法大规模的应用到所有垃圾回收中。可以使用在新生代中,新生代中的对象的生命周期比较短,适合这个算法
Cheney算法采用一种复制的方式实现的垃圾回收算法。将堆内存一分为二,每一部分空间称为semispace。在两个semispace空间中,只有一个处于使用中,另一个处于闲置中,处于使用状态的空间称为From空间。处于闲置状态的空间称为To空间。在分配对象的时候,先在From空间中进行分配,开始垃圾回收的时候,会检查from空间中的存活对象,这些存活对象被复制到to空间中,不是存活对象被释放。完成复制后,from和to的空间发生对调。
当一个对象经过多次复制还存活的时候,会被认为是生命周期比较长的对象,这种比较长的生命周期随后会被移动到老生代中,采用新的算法进行管理。对象从新生代移动到老生代称为晋升
在单纯的Scavenge过程中,From空间中的存活对象会复制到to空间中,然后from空间和to空间进行角色互换,但是在分代垃圾回收的前提下,from空间的存活对象在复制到to空间前要进行一系列的检查,在一定条件下,需要将存活周期长的对象移动到老生代中,也就是完成对象晋升。
对象晋升的条件 => 1. 对象是否经过scavenge回收 2. to空间的内存占用比超过限制
v8的对象分配集中在from空间中,对象从from空间中复制to空间的时候,会检查他在内存地址中来判断这个对象是否已经经历过一个scavenge回收,如果已经经历过,会将该对象从from空间复制到老生代空间中,如果没有就复制到to空间
另一个判断是to空间的内存占用比,当要从from空间复制一个对象到to空间中,如果to空间的内存使用超过了25%,这个对象会被直接晋升到老生代中
设置25%这个限制值的原因是当这次scavenge回收完成之后,这个to空间将变成from空间,接下来的内存分配在这个空间中进行,如果占比过高,就会影响后续的内存分配。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传