筆記五:JavaScript性能優(yōu)化

內(nèi)存管理

內(nèi)存管理介紹

  • 內(nèi)存:由可讀寫單元組成,表示一片可操作空間
  • 管理:認為的去操作一篇空間的申請、使用和釋放
  • 內(nèi)存管理:開發(fā)者主動申請空間、使用空間、釋放空間
  • 管理流程:申請-使用-釋放

垃圾回收與常見GC算法

JavaScript中的垃圾

  • JavaScript中內(nèi)存管理是自動的
  • 對象不在被引用時是垃圾
  • 對象不能從根上訪問到時時垃圾

JavaScript中的可達對象

  • 可以訪問到的對象就是可達對象(引用、作用域鏈)
  • 可達的標準就是從根出發(fā)是否能夠被找到
  • JavaScript中的根就可以理解為時全局變量對象

GC算法

GC定義與作用
  • GC就是垃圾回收機制的簡寫
  • GC可以找到內(nèi)存中的垃圾、并釋放和回收空間
GC里的垃圾是什么
  • 程序中不在需要使用的對象
  • 程序中不能再訪問到的對象
GC算法
  • GC是一種機制,垃圾回收器完成具體的工作
  • 工作的內(nèi)容就是查找垃圾釋放空間、回收空間
  • 算法就是工作時查找和回收所遵守的規(guī)則
常見GC算法
  • 引用計數(shù)
    • 核心思想:設置引用數(shù),判斷當前引用數(shù)是否為0
    • 引用計數(shù)器
    • 引用關系改變時修改引用數(shù)字
    • 引用數(shù)字為0時立即回收
      引用計數(shù)算法優(yōu)缺點
      • 發(fā)現(xiàn)垃圾時立即回收
      • 最大限度減少程序暫停執(zhí)行(程序卡頓時間)
      • 無法回收循環(huán)引用的對象
      • 時間開銷大(資源消耗大)
  • 標記清除
    • 核心思想:分標記和清楚兩個階段
    • 遍歷所有對象找到標記活動對象
    • 遍歷說有對象清除沒有標記對象
    • 回收相應的空間
      標記清除算法優(yōu)缺點
    • 解決了引用計數(shù)中無法回收循環(huán)引用的對象
    • 會產(chǎn)生空間碎片化的問題,使得空間不能最大化的使用
    • 不會立即回收垃圾對象(在回收垃圾時程序時停止執(zhí)行的)
  • 標記整理
    • 標記整理可以看作時標記清除的增強
    • 標記階段的操作和標記清除一致
    • 清除階段會執(zhí)行整理,移動對象的位置,使它們在地址上連續(xù)
      標記整理算法優(yōu)缺點
    • 減少碎片化空間
    • 不會立即回收垃圾對象(在回收垃圾時程序時停止執(zhí)行的)
  • 分代回收

V8引擎的垃圾回收

V8是一款主流的JavaScript執(zhí)行引擎,采用即時編譯,內(nèi)存設有上限,采用分代回收思想實現(xiàn)垃圾回收,內(nèi)存分為新生代和老生代

回收策略
  • 采用分代回收策略
  • 內(nèi)存分為新生代、老生代
  • 針對不同的對象采用不同的算法
V8常用GC算法
  • 分代回收
  • 空間復制
  • 標記清除
  • 標記整理
  • 標記增量
V8如何回收新生代對象
V8內(nèi)存分配
  • V8內(nèi)存空間一分為二
  • 小空間用于存儲新生代對象(32M | 16M)
  • 新生代指的是存貨時間較短的對象
新生代對象回收實現(xiàn)
  • 回收過程采用復制算法+標記整理
  • 新生代內(nèi)存區(qū)分為兩個等大小空間
  • 使用空間為From,空閑空間為To
  • 活動對象存儲于From空間
  • 標記整理后將活動對象拷貝至To空間
  • From與To交換空間完成釋放
回收細節(jié)說明
  • 拷貝過程中可能出現(xiàn)晉升
  • 晉升就是將新生代對象移動至老生代
  • 一輪GC還存貨的新生代需要晉升
  • To空間的使用率超過25%
V8如何回收老生代對象
老生代對象說明
  • 老年代對象存放在右側老生代區(qū)域
  • 64位操作系統(tǒng)1.4G,32位操作系統(tǒng)700M
  • 老生代對象就是指存輝時間較長的對象
老生代對象回收實現(xiàn)
  • 主要采用標記清除、標記整理、增量標記算
  • 首先使用標記清除完成垃圾空間的回收
  • 采用標記整理進行空間優(yōu)化(新生代晉升老生代過程中,發(fā)現(xiàn)老生代空間不足時)
  • 采用增量標記進行效率優(yōu)化
細節(jié)對比
  • 新生代區(qū)域垃圾回收使用空間換時間(使用復制算法)
  • 老生代區(qū)域垃圾回收不適合復制算法

Performance工具

為什么使用Performance

  • GC的目的是為了實現(xiàn)內(nèi)存空間的良性循環(huán)
  • 良性循環(huán)的基石時合理使用
  • 時刻關注才能確定是否合理
  • Performance提供更多監(jiān)控方式

Performance使用步驟

  • 打開瀏覽器輸入目標地址
  • 進入開發(fā)人員工具面板,選擇性能(Performance)
  • 開啟錄制功能,訪問具體頁面
  • 執(zhí)行用戶行為,以斷事件后停止錄制
  • 分析界面中記錄的內(nèi)存信息

內(nèi)存問題的外在表現(xiàn)

  • 頁面出現(xiàn)延遲或經(jīng)常性暫停(保證網(wǎng)絡正常情況下)
  • 頁面持續(xù)性出現(xiàn)糟糕的性能(保證網(wǎng)絡正常情況下)
  • 頁面的性能隨時間延長越來越差(出現(xiàn)內(nèi)存泄漏)

監(jiān)控內(nèi)存的幾種方式

界定內(nèi)存問題的標準
  • 內(nèi)存泄漏:內(nèi)存使用持續(xù)升高
  • 內(nèi)存膨脹:在多數(shù)設備上都存在性能問題
  • 頻繁垃圾回收:通過內(nèi)存變化圖進行分析
幾種監(jiān)控方式
  • 瀏覽器任務管理器
  • TimeLine時序圖記錄
  • 堆快照查找分離DOM
  • 判斷是否存在頻繁的垃圾回收

代碼優(yōu)化實例

如何和精準測試JavaScript性能

  • 本質(zhì)上就是采集大量的執(zhí)行樣本進行數(shù)學統(tǒng)計和分析
  • 使用基于Benchmark.js的https://jsperf.com/完成

Jsperf使用流程

  • 使用GitHub帳號登錄
  • 填寫個人信息(非必填)
  • 填寫詳細的測試用例信息(title、slug)
  • 填寫準備代碼(DOM操作時經(jīng)常使用)
  • 填寫必要的setup與teardown代碼
  • 填寫測試代碼片段

為什么要慎用全局變量

  • 全局變量定義在全局執(zhí)行上下文,是所有作用域鏈的頂端
  • 全局執(zhí)行上下文一直存在與上下文執(zhí)行棧,直到程序退出
  • 如果某個局部作用域出在線了同名變量則會遮蔽或污染全局

緩存全局變量

  • 將使用中無法避免的全局變量緩存到局部(document緩存)

通過原型對象添加附加方法

避免閉包陷阱

避免屬性訪問方法使用

For循環(huán)優(yōu)化

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容