js效能優化相關內容筆記整理

路飛的笑發表於2021-12-27

GC 演算法

1. 引用計數

核心思想:設定引用數,判斷當前引用是否為0

優點:

  1. 發現垃圾時,立即回收
  2. 最大限度減少程式暫停

缺點:

  1. 無法回收迴圈引用的物件
  2. 時間開銷大(需要監聽計數值的變化)
function fn() {
    const obj1 = {}
    const obj2 = {}
}

2. 標記清除

核心思想:分標記和清除兩個階段

缺點:
1、 空間碎片化(回收物件在地址上的不連續)
2、 不能立即回收

3. 標記整理

標記,然後將活動物件的地址進行整理,儘量使得活動物件地址連續

4. 分代回收

回收新生代物件(存活時間較短的變數物件)
  • 回收過程採用複製演算法+標記整理
  • 新生代記憶體區分為兩個等大小的空間
  • 使用空間為From,用於儲存活動物件, 空閒空間為To,用於儲存From中的活動物件
  • 活動物件儲存於From空間
  • 標記整理後將活動物件拷貝至To
  • From 與To交換空間完成釋放

回收細節:From和To之間的拷貝過程可能出現晉升(將新生代物件移動至老生代)下面兩種情況會產生晉升

  • 一輪GC後還存活的新生代需要晉升
  • To空間的使用率超過了25%
回收老生代物件

空間大,無法使用複製演算法,使用增量標記法優化效率

  • 標記清除
  • 標記整理: 使得活動物件的地址連續
  • 標記增量: 將原本標記整理的工作拆分為多個小的標記工作,防止程式阻塞

V8

v8垃圾回收策略

v8記憶體有上限

  1. 採用分代回收思想
  2. 記憶體分為新生代,老生代
  3. 針對不同物件,採用不同演算法

常用演算法

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

頻繁GC(垃圾回收)會帶來什麼

  • GC工作時,應用程式是停止的
  • 頻繁且過長的GC會導致應用假死
  • 使用者使用中感知應用卡頓

如何確定是否頻繁回收垃圾:

  • Timeline中頻繁的上升下降
  • 工作管理員中資料頻繁的增加減小

堆快照查詢分離dom,這個都是無用的dom引用,需要使用堆快照功能超找
detachedNode
image.png

v8引擎執行流程

image.png

程式碼優化 函式巢狀會導致v8進行多次的預解析,因此不要巢狀太深

堆疊操作

  • js執行環境
  • 執行環境棧(ECStack, execution context stack)
  • 執行上下文
  • VO(G),全域性變數物件
  • EC(G),全域性執行上下文

基本型別 (棧操作)

  • 基本資料型別是按值進行操作
  • 基本資料型別值是存放在區的
  • 無論我們當前看到的棧記憶體,還是後續引用資料型別會使用的堆記憶體都屬於計算機記憶體
  • GO(全域性物件)

引用型別 (堆操作)

  1. 函式執行

    1. 確定作用域鏈(當前執行上下文,上級執行上下文)
    2. 確定this指向,如果是在全域性作用域那麼就是window
    3. 初始化arguments物件
    4. 形參賦值
    5. 變數提升(var宣告的關鍵字,或者函式內部的function宣告)
    6. 執行程式碼
    7. 如果函式內部沒有被其他地方所引用,那麼就會進行出棧操作,釋放棧記憶體
  2. 閉包理解

    function fn() {
     var a = 1
     return function(b) {
         console.log(a + b)
     }
    }
    const f = fn()
    f(5)
    f10()
    1. 閉包是一種機制,通過私有的上下文來保護其中的變數的一種機制
    2. 也可以認為,在建立的某一個執行上下文不被釋放的時候 就形成了閉包
    3. 保護、儲存資料

迴圈新增事件,看閉包使用的取捨

如果使用閉包,進行多個事件的註冊,因為閉包的原因,會申請一個對地址來儲存,如果事件越多,那麼申請的記憶體越多,因此需要用到事件代理

變數的申明

變數申明最好是放在區域性變數,否則程式碼在執行的時候 查詢作用域鏈上的變數會比較花時間, 對比下面兩段程式碼 使用的是 jsbench這個工具

var i, str = ""

function parseDom() {
   for(i = 0; i < 100; i++) {
       str += i
   }
}
parseDom()

function parseDom() {
   let str = ''
   for(let i = 0; i < 100; i++) {
       str += i
   }
}
parseDom()

image.png

變數快取
  • 陣列長度
  • 多次使用的dom變數等
減少判斷層級
  • 儘可能的減少判斷的層級,如果有巢狀判斷,看看是否可以將判斷條件往外提
減少迴圈體活動

相關文章