1.同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
2.DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。
3.通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
4.脚本限制
Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
5.文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。
node基于v8构建,所以在node中使用的js对象基本上都是通过v8自己的方式来进行分配和管理的。
在v8中,所有的js对象都是通过堆来进行分配的。
process.memoryUsage()
{
rss:24473600,
heapTotal: 7331840,
heapUsed: 5736952,
external: 8727
}
v8内存分代
v8中,主要将内存分为新生代和老生代。新生代中为存活时间较短的对象,老生代中为存活时间较长的对象。
新生代垃圾回收:
新生代中的对象主要通过Scavenge算法进行垃圾回收。将新生代中的内存空间一分为二,处于使用状态的为From空间,处于闲置状态的为To空间。在进行垃圾回收时,检查From空间的存活对象并复制到To空间,非存活对象占用空间释放。之后From和To空间角色对调。
对象晋升:
如果一个对象经历过一次新生代垃圾回收,或者To空间的内存占比超过25%,则此对象从新生代中移动到老生代中,此过程称为晋升。
老生代垃圾回收:
主要采用Mark-Sweep(标记清除)和Mark-Compact(标记整理)两种方式进行垃圾回收。
标记清除在标记阶段遍历堆中的所有对象,并标记活着的对象。随后的清除中只清除没有被标记的对象。会产生内存碎片。为解决这个问题,标记整理被提了出来,在对象被标记为死亡后,在整理的过程中,将活着的对象往一端移动,移动完成后直接清理掉边界外的内存。v8中混合使用这两种方法。一般在空间不足以对从新生代晋升过来的对象进行分配时,才使用标记整理。
高效使用内存:
在js中无法立即回收的内存有闭包和全局变量引用这两种情况。此情况会导致新生代中的对象数量增多。
导致的问题: Node 无法直接操作大文件对象。
例如我想读取一个 4g 的文件来处理,即使物理内存有 32GB,在单个 Node 进程中也是不能完全的使用的。
我们平常在声明一些对象的时候,要是没有Node垃圾回收机制回收 ,就会占用V8限制的内存
内存限制主要原因是v8的垃圾回收制度。1.5GB内存做一次小的回收需要50MS,做一次非增量性回收需要1S以上,并且这会使JS线程暂停。因此限制内存。
所有的 JS 对象都是通过堆来进行分配的。
可以使用Buffuer,因为Buffer不受V8的内存分配机制,
Node.js程序所使用的内存分为两类:
在程序允许的情况下,应该将数据保存在 Buffer 中,而不是转换成字符串等JS对象,这样可以避免 V8 内存的过多占用。
process.nextTick()会在本次事件循环结束后,立即开始下次事件循环。这样可以使V8获得内存回收的机会,有效解决过多事件堆积造成的内存溢出。
我们可以使用process.nextTick()方法处理:
每次循环V8都会回收内存一次,因此内存不会再溢出。但这样做必然会造成运行效率的降低,而应该在速度在安全之间平衡,控制好循环的安全次数。
官方建议:it is recommended that you split your single process into several workers if you are hitting memory limits. (拆分进程)