不归 libUV管的几个api ---- 用观察者监控
// 追加在次轮循环的异步任务 详情见大神的图
setTimeout(function () {
console.log(1);
}, 0);
// 追加在次轮循环的异步任务 详情见大神的图
setImmediate(function () {
console.log(2);
});
// 异步 三
// 同步任务执行完毕后立即执行 追加在本轮循环的异步任务
process.nextTick(() => {
console.log(3);
});
new Promise((resolve, reject) => {
// 同步 一
console.log(4);
resolve(4);
}).then(() => {
// 四 追加在本轮循环的异步任务 微任务队列,在宏任务队列后面
console.log(5);
});
// 同步 二
console.log(6);
// 4
// 6
// 3
// 5
// 1
// 2
V8垃圾回收机制
操作文件大小限制
Node 使用 JavaScript 在服务端操作大内存对象受到了一定的限制(堆区),64位系统下约为1.4GB,32位操作系统下是0.7G。栈区新生代64位是32M,32位是16M。
垃圾回收机制
V8的垃圾回收策略主要基于
分代式垃圾回收机制。
在自动垃圾回收的演变过程中,人们发现没有一种垃圾回收算法能够胜任所有场景。
V8中内存分为新生代和老生代两代。
新生代为存活时间较短对象,老生代中为存活时间较长的对象。
新生代算法(满了就回收)
在分代基础上,新生代的对象主要通过
Scavenge算法进行垃圾回收,再具体实现时主要采用Cheney算法。
Cheney算法是一种采用复制的方式实现的垃圾回收算法。
它将内存一分为二,每一个空间称为semispace。这两个semispace中一个处于使用,一个处于闲置。
处于使用的称之为From,闲置的称之为To。
分配对象时先分配到From,当开始进行垃圾回收时,检查From存活对象赋值到To。
非存活被释放(垃圾回收)。然后互换位置。
再次进行回收,发现之前交换过直接晋升,或者发现To空间已经使用了超过25%。
他的缺点是只能使用堆内存的一半,这是一个典型的空间换时间的办法,但是新生代声明周期较短,恰恰就适合这个算法。
- 两个指针是重合的。
scanPointer(扫描)指针从from的头部开始运动,每当出现还在使用的代码,allocatePointer(存储)指针就会移动同样空间的距离。scanPointer(扫描)指针移动到allocatePointer(分配)指针的位置,并把内容放到新腾出来的空间里。scanPointer(扫描)指针回去继续工作,直到所有该放的都放了。- 两个指针又重合了
老生代算法(一会儿就去回收一次)
V8 老生代主要采用
Mark-Sweep和Mark-compact。(使用Scavenge不合适。因为对象较多需要赋值量太大而且还是没能解决空间问题。)
Mark-Sweep是标记清除,标记那些死亡的对象,然后清除。
但是清除过后会出现内存不连续的情况,所以我们要使用Mark-compact,他是基于Mark-Sweep演变而来的。
他先将活着的对象移到一边,移动完成后,直接清理边界外的内存。
当CPU空间不足的时候会非常的高效。
V8后续还引入了延迟处理,增量处理,并计划引入并行标记处理。