快速學習nodejs系列:11、nodejs垃圾回收

nodejs的垃圾回收機制是由v8引擎自動管理的。php

nodejs的內存限制
在通常的後端語言(php)來講,內存的使用上是沒有限制的,但對於nodejs來講只能使用系統的部分----64位系統爲1.4G,32位系統位0.7G。這時若是你要處理個3G文件進行數據分析,即便系統的內存爲8G,在該nodejs進程內存仍是會溢出。node

形成上面這個問題主要是由於nodejs是基於v8的,nodejs是經過v8本身的方式來管理內存的。那v8爲何要限制堆內存的大小呢?緣由有2:
1.表層緣由:v8是爲瀏覽器設計的,不大可能遇到大內存的情景。
2.深層緣由:v8垃圾回收機制的限制。以1.5G的堆內存爲例,v8作一次小的垃圾回收須要50ms,作一次非增量的垃圾回收要1s。垃圾回收時會引發js的線程的暫停,在這樣的時間花銷下,應用的性能、響應能力會直線降低。
內存限制是能夠打開的:
--max-old-space-size(老生代)
--max-new-space-size(新生代)
v8堆內存大小 = 老生代 + 新生代web

v8垃圾回收機制
v8垃圾回收主要是基於分代式垃圾回收機制。按對象的存活時間將內存的垃圾回收進行不一樣的分代,分別對不一樣的分代內存進行不一樣的算法。算法

新生代--->存活時間較短的對象
老生代--->存活時間較長或常駐內存的對象
上面也說過,nodejs堆內存的大小是新生代內存空間加上老生代內存空間。後端

新生代算法
新生代主要是經過scavenge算法進行垃圾回收。數組

這是一種採用複製的方式來實現垃圾回收,將堆內存一分爲二,每一個空間稱爲semispace。在這2個semispace空間中,只有一個處於使用中(稱爲from空間),另外一個處於空閒中(稱爲to空間)。開始分配時首先從from空間開始,當開始垃圾回收時,也是從from空間開始檢查存活對象,把存活對象複製到to空間,而非存活對象佔用的空間就會被釋放。完成複製後,from空間和to空間角色對調。
從上面的過程能夠知道,scavenge的缺點就是隻使用了一半的堆內存,犧牲空間獲取時間。瀏覽器

老生代經過mark-sweep、mark-comopact算法。session

mark-sweep標記清除,分爲標記、清除2個階段。mark-sweep先在標記階段遍歷堆內存中的全部對象,並標記存活的對象;在清除階段把沒有被標記的對象清除。能夠看出,scavenge只複製存活的對象,mark-sweep只清理死亡的對象。由於在新生代中存活的對象佔用小部分,而在老生代中死亡對象佔用小部分,這是這2中算法高效的緣由。性能

Mark-compact標記整理,mark-sweep中會出現一個問題,在回收後,對內存會出現不連續的狀態(內存碎片)。內存碎片會對後續的內存分配形成影響,由於會有這樣一種狀況:須要分配個大內存,而全部內存碎片都沒法完成分配,這會提早觸發垃圾回收,而這個回收時沒必要要的。Mark-compact是在Mark-sweep基礎上演變而來的,它主要區別在於:對象被標記後,在整理的過程當中會將存活的對象都往一端移動,移動完成後直接清除。spa

小結:在正常的使用過程當中,v8的內存限制仍是夠用的,但nodejs的垃圾回收、單線程仍是會影響性能。想要高性能,須要讓垃圾回收儘可能小。在實際的開發中要老生代對象的使用,如實現web服務的會話(session),通常會經過內存來存儲(數組),在訪問量大的狀況下會致使老生代對象劇增,有可能形成溢出。若是要處理大內存的數據,好比讀取3G的文件,咱們會經過可讀流的pipe()方法,這樣就不會受到v8內存的限制影響,提升了nodejs程序的健壯性。

相關文章
相關標籤/搜索