JS性能優化1

從本文你將瞭解到

  • 內存管理
  • 垃圾回收與常見的 GC算法
  • V8引擎的垃圾回收

JS性能優化是提升運行效率,下降運行開銷的行爲前端

前端性能優化無處不在,例如請求資源時的網絡,數據的傳輸方式,開發時使用的框架等c++

js內存管理
爲何須要管理(如圖查看內存佔用狀況)算法

內存:由可讀寫單元組成,表示一片可操做空間瀏覽器

管理:人爲的去操做一片空間的申請,使用和釋放性能優化

內存管理:開發者主動申請空間,使用空間,釋放空間網絡

流程:申請-使用-釋放閉包

因爲es中沒有提供相應的內存管理API,因此JS不能像c,c++同樣由開發者主動調用相應API完成空間管理框架

//申請(js執行引擎遇到變量定義語句時自動分配內存空間)
let obj = {}

//使用
obj.name = "mcgee"

//釋放
obj = null

js中的垃圾回收前端性能

js中的內存管理是自動的函數

  • 對象再也不被引用時是垃圾
  • 對象不能從根上訪問到時是垃圾

js中的可達對象

能夠訪問到的對象就是可達對象(引用,做用域鏈)

可達的標準就是從根出發是否可以被找到

js中的根就能夠理解爲全局變量對象

//mcgee對象空間被nm引用。在全局執行上下文下,nm是可達的對象,間接意味着mcgee對象空間也是可達的
let nm = {name:"mcgee"}
//對象空間又多了一層引用
let ali = nm
//去除nm對對象的引用
nm = null
function objGroup(obj1,obj2){
  obj1.next = obj2
  obj2.prev = obj1

  return {
    o1:obj1,
    o2:obj2
  }
}

const result = objGroup({name:"obj1"},{name:"obj2"})
console.log(result)

若是我要刪除obj1 圖解上述代碼

GC算法

垃圾回收機制的簡寫

GC能夠找到內存中的垃圾,並釋放和回收空間

GC是一種機制,垃圾回收器完成具體的工做,工做的內容就是查找垃圾釋放空間,回收空間

算法就是工做時查找和回收所遵循的規則

  • 引用計數
  • 標記清除
  • 標記整理
  • 分代回收
//程序中再也不須要使用的對象 (fn方法)
function fn(){
  name = "aa"
  return name
}
fn()

//程序中不能再訪問到的對象 (name)
function fn1(){
  const name = "aa"
  return name
}
fn1()
  • 引用計數算法

設置引用數,判斷當前引用數是否爲0

引用計數器:GC經過判斷引用計數器是否爲0判斷是否須要內存回收

優缺點:

  • 優勢:發現垃圾時當即回收,最大限度的減小程序的暫停
  • 缺點:沒法回收循環引用對象,時間開銷大
function fn2(){
  const name = "aa"
  return name
}
fn2()//執行完後,函數內name變量的引用計數變成0,fn2所佔的內存被回收釋放

const o = {
  age:19
}
const ls = o.age //o的對象在ls處有引用,o在內存沒法被釋放

//obj1和obj2循環引用
function objGroup(obj1,obj2){
  obj1.next = obj2
  obj2.prev = obj1

  return {
    o1:obj1,
    o2:obj2
  }
}
  • 標記清除算法

將垃圾回收操做分紅兩個階段 標記階段和清除階段

  • 標記階段:遍歷全部對象(遞歸查找)給活動對象標記
  • 清除階段:遍歷全部的對象清除沒有標記對象(看圖內部可能有a1,b1未被標記的私有變量),同時清除全部標記

優缺點:

  • 優勢:解決對象循環引用的回收操做
  • 缺點1:空間碎片化(看圖) 空間地址(分兩部分,頭和域) 頭存元信息(大小地址) 域存放數據。藍色的內存空間很碎,回收的空間不集中。
  • 缺點2:不會當即回收垃圾對象

當釋放的空間內存地址不連續,致使分散再空閒列表的角落,致使下次再使用內存不太適合再使用
  • 標記整理算法

標記清除的加強操做,標記階段與標記清除算法一致

整理階段:會在清除以前,先執行整理,移動對象,使釋放的地址連續,再執行清除操做

優缺點:

  • 優勢:減小碎片化空間
  • 缺點:不會當即回收垃圾對象

V8引擎介紹

  • 主流JS執行引擎(瀏覽器,Node)
  • V8採用即時編譯(其餘js引擎須要將源代碼轉化成字節碼,而後再執行,而V8將源碼翻譯成可直接執行的機器碼)
  • V8內存設限 64x 1.5G | 32x 800M
  • 爲何設限:自己爲瀏覽器設置的,針對於外部應用來講這樣的內存大小是足夠使用的,由內部的垃圾回收機制決定,若是內存再大一些,回收時間可能超過用戶的感知
  • V8垃圾回收策略

    • 採用分代回收的思想
    • 內存分爲新生代,老生代
    • 針對不一樣對象(代)採用不一樣算法(如圖)

V8中經常使用GC算法

  • 分代回收
  • 空間複製
  • 標記清除
  • 標記整理
  • 標記增量

V8內存分配(如圖)

  • V8內存空間一分爲二,新生代對象和老生代對象
  • 小空間(新生代)用於存儲新生代對象(64x 32M|32x 16M)
  • 新生代指的是存活時間較短的對象,(私有變量)

新生代對象回收實現

  • 回收過程採用複製算法+標記整理
  • 新生代內存區分爲兩個等大小空間
  • 使用空間爲From,空閒空間爲To
  • 活動對象存儲於From空間
  • 觸發GC機制後,標記整理From內的活動對象,後將活動對象拷貝至To
  • From與To交換空間完成釋放

回收細節說明

  • 拷貝過程當中可能出現晉升(某個活動對象在老生代內存中也會出現)
  • 晉升就是將新生代對象移動至老生代
  • 一輪GC還存活的新生代須要晉升
  • To空間的使用率超過25%須要晉升

V8如何回收老生代對象

  • 老生代對象對象說明
  • 老生代對象存放在右側老生代區域(64x 1.4G | 32x 700M)
  • 老生代對象就是指存活時間較長的對象(閉包,全局變量)

老年代對象回收實現

  • 主要採用標記清除,標記整理,增量標記算法
  • 首先使用標記清除完成垃圾空間的回收
  • 當新生代內存向老生代區域移動的時候,且老生代存儲區空間又不足存放新生代存儲區所移過來的對象(也就是晉升),採用標記整理進行空間優化
  • 採用增量標記的方式進行效率優化

增量標記垃圾回收(如圖)

  • 垃圾回收工做時會阻塞js的執行
  • 讓垃圾回收和程序交替執行,而不是一次性執行垃圾回收
  • 先找到第一層可達對象標記一輪,而後執行GC回收,再遞歸第二層可達函數,再進行GC回收

新老生代對比

  • 新生代區域垃圾回收使用空間換時間
  • (由於它採用複製算法,每時每刻都有空閒空間存在,可是因爲新生代空間自己就很小,分出來的空間就更小,因此空間上的浪費相對於時間上的提高是微不足道的)
  • 老生代區域垃圾回收不適合複製算法
  • (空間大,複製幾百M空間,會有空間浪費,且存放的數據較多,複製消耗時間過大)

總結

  • v8主流js執行引擎
  • v8內存設置上限
  • v8採用基於分代回收思想實現垃圾回收
  • v8內存分爲新生代和老生代
  • v8垃圾回收常見的GC算法(新生代複製+標記整理,老生代標記清除,標記整理,增量標記)

我的總結

  • 內存,可讀寫單元組成的操做空間
  • 內存管理,申請使用釋放
  • js裏沒有處理內存的API,內存管理是自動的
  • 經過js垃圾回收進行自動處理
  • 處理對象是沒有引用的對象,從根(全局對象)出發訪問不到的對象
  • GC機制是查找垃圾,釋放空間,回收空間
  • 算法有 引用計數算法,標記清除, 標記整理, 分代回收
  • V8引擎
  • 主流瀏覽器引擎
  • 採用及時編譯
  • 內存設限1.5g 800m
  • V8採用分代GC回收思想
  • 將內存分爲新生代區域和老生代區域,不一樣區域不一樣處理
  • 新生代gc
  • 新生代區域內存 32m,16m
  • 新生代gc回收 複製算法+標記整理
  • 新生代分爲from+to兩個空間
  • 活動對象都在from裏,to裏是空閒空間
  • 觸發gc時,會堆from內的對象進行標記整理(兩次for)
  • 而後from,to交換空間進行釋放
  • 在執行過程當中,一輪gc後還存活(還有引用的要晉升(將新生代對象移至老生代空間))
  • 在執行過程當中,to空間使用率超25%要晉升
  • 老生代gc
  • 標記清除,標記整理,增量標記
  • 增量標記是讓垃圾回收和程序交替執行,而不是一次性執行垃圾回收
相關文章
相關標籤/搜索