js worker主线程和子线程内存是怎么分配

JavaScript012

js worker主线程和子线程内存是怎么分配,第1张

按照如下步骤分配:

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. (拆分进程)