Node.js——nodejs(內存控制)(轉)


node使用V8作為javaScript腳本引擎

v8的內存限制和對象分配

限制:64為大約1.4G,32位大約0.7G
v8中所有javascript對象都是通過堆內存進行分配的。內存查看命令process.memoryUsage()

為何要內存限制

表層原因為v8最初為瀏覽器設計,不太可能遇到大量的內存的場景。對於網頁來說,v8的限制已經綽綽有余,深層原因是v8的垃圾回收機制的限制.
v8打開堆內存的限制命令 --max-old-space-size或--max-new-space-size

v8的垃圾回收機制

v8的內存分代

主要將內存分為新生代和老生代。新生代中為存活時間交短的對象,老生代中的對象為存活時間較長或者常駐內存對象

  • 新生代內存在64位系統中為16MB,32位中為8MB
  • v8堆內存最大保留空間 4 * 新生內存 + 老生代內存

新生代內存垃圾回收

采用一種復制方式的垃圾回收算法,將堆內存一分為二,只有一部分空間被使用稱為From空間,另一個處於閑置稱為To空間。當進行分配對象的時候先在from空間分配,當進行垃圾回收時,會檢查from空間中的存活對象,將這些存活對象復制到to空間中,復制完成后From和to空間角色互換,清空to空間,在垃圾回收過程中就是通過將存活對象在兩個空間中進行復制。

  • 缺點: 只能使用一半的內存
  • 優點: 只復制存活的對象,對於生命周期短的場景存活對象只占小部分,所以時間效率高
    當一個對象經過多次復制依然存活時,就會被認為是生命周期較長的對象,會被移入老生代內存中。
    對於移入老生代內存有兩個條件:
  • 對象已經經過新生代內存回收機制的回收依然存活
  • 復制到To空間的對象超過25%(為什么是25%?這個To空間接下來會成為From空間並接受內存分配,如果占比過高影響后續分配)

老生代內存垃圾回收

采用標記清除,它分為標記清除兩個階段
在標記階段遍歷所有的對象並標記活着的對象,在清除階段只清除死亡的對象,死亡對象在老生代內存只占一小部分。老生代內存進行一次清除后,內存空間會出現不連續的狀態,所以清理完成需要進行一步標記整理。

為了避免出現javaScript應用邏輯與垃圾回收器看到不一致的情況,垃圾回收都要將應用邏輯停下來,這種行為會造成停頓,在新生代垃圾回收過程中因為存活對象比較少,即使停頓基本影響不大。在老生代垃圾回收中,通常存活對象較多,全堆垃圾回收的標記、清除、整理影響較大。
解決辦法:分批次進行,拆分成許多小步,每進行一小步就讓邏輯運行一會

node 查看垃圾回收日志 運行時加入 參數 --trace_gc

高效使用內存

作用域

減少使用全局作用域,在局部作用域聲明變量。當函數執行完成,該作用域就會被銷毀,只別局部變量引用的對象存活較短,會被分配到新生代內存,方便回收

閉包

function test() { var a = 1 return function () { return a } } var fn1 = test() 

堆外內存

通過命令process.memoryUsage() 可以查看代rss總是大於常駐內存總量,在node中並不是所有的內存都通過v8進行分配,不通過v8進行分配的內存稱為堆外內存,通過Buffer 分配的內存即為堆外內存,所有處理大量數據的時候可以使用Buffer 進行分配

內存泄漏

通常造成內存泄漏的原因有:

  • 緩存
  • 隊列消費不及時
  • 作用域未釋放

慎用內存當緩存

緩存的訪問效率要比I/O的效率高很多,一旦命中緩存,就可以節省一次I/O的時間,但是在node中,一旦一個對象被當作緩存,那它將常駐老生代內存,緩存中儲存的鍵越多,長期存活的對象就越多,這將導致垃圾回收在進行掃描和整理是頻繁的多這些對象做無用功。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM