javascript垃圾收集與性能問題

来源:https://www.cnblogs.com/eveningwater/archive/2018/03/04/8506126.html
-Advertisement-
Play Games

一.垃圾收集 JavaScript具有自動垃圾收集功能,也就是說,執行環境會負責管理代碼所占用的記憶體. 不同於C和類C語言,這些語言都需要手動監聽記憶體的使用情況.JavaScript實現了自動管理記憶體,我們無需擔心這個問題. 這種垃圾收集器的原理也很簡單,就是找出不再繼續使用的變數,然後釋放其占用的 ...


一.垃圾收集

 

    JavaScript具有自動垃圾收集功能,也就是說,執行環境會負責管理代碼所占用的記憶體.

不同於C和類C語言,這些語言都需要手動監聽記憶體的使用情況.JavaScript實現了自動管理記憶體,我們無需擔心這個問題.

這種垃圾收集器的原理也很簡單,就是找出不再繼續使用的變數,然後釋放其占用的記憶體.垃圾收集器會按照固定的時間間隔(或者代碼的執行時間)來周期性的重覆這個操作.

 

對於局部變數,我們都知道一旦在函數運行完成之後,函數和局部變數就立即被銷毀,所以,此時局部變數也就沒有存在的意義了.因此,我們可以釋放局部變數的記憶體.垃圾收集器會自動為無用的變數做上標記,然後回收其占用的記憶體.具體所用到的策略會因瀏覽器而異.但總的來說,就只有二個策略.

 

1.標記清除

 

 標記清除是JavaScript中最常見的垃圾收集方式了.當變數進入一個執行環境,這個變數就會被標記為進入環境,因此,永遠都不能釋放進入環境的變數,因為只要執行流進入相應的環境,還有可能會運用到它們,當變數離開環境之後,就會將其標記為離開環境..

 

可以使用任意方式標記一個變數,因此,如何標記變數並不重要,重要的是採用什麼策略.

 

垃圾收集器在運行的時候會給存儲在記憶體中的所有變數加上標記.然後,它會去掉環境中的變數以及被環境中變數引用的變數的標記.在此之後,加上標記的變數就是被視為準備刪除的變數,因為環境中的變數已經無法訪問到這些變數了,最後垃圾收集器完成清除記憶體的工作,銷毀哪些帶標記的值並回收它們所占用的記憶體空間.

 

2.引用計數

 

另一種不太常見的垃圾收集策略叫做引用計數.引用計數的含義就是跟蹤每個值被引用的次數.當聲明一個變數並將這個變數賦一個引用類型的值時,引用次數就為1,如果將相同的值又被賦予另一個變數,則引用次數記為2,如果包含這個值引用的變數又引用其它值,則減1.當這個值的引用次數變成0時,則說明無法訪問這個值了,就會回收這個值所占用的記憶體.這樣,當垃圾收集器下次運行時,就會自動釋放那些引用次數為0的值所占用的記憶體.

 

Netscape Navigator3.0是最早使用引用計數策略的瀏覽器,然而很快這個策略就暴露了一個嚴重的問題——迴圈引用.所謂迴圈引用,指的就是一個對象A包含指向一個對象B的指針時,對象B也有包含指向對象A的指針引用.如下圖一個示例:

 

 

如上圖所示,person對象和people對象都通過各自的屬性相互引用,也就是說這兩個對象的引用次數始終都是2.如果是採用標記清除的策略,因為函數執行完成之後,這兩個對象都離開了作用域,因此這種相互引用還並不是問題.但在採用引用次數策略的時候,由於引用次數始終都是2,始終都不為0,假如這個函數被多次調用的話,就會占用大量記憶體得不到回收.

 

所以,Netscap4.0就放棄了引用計數的策略,而採用標記策略,但這個問題並沒有終結.

 

因為IE中有一部分對象並不是原生JavaScript對象,比如BOM和DOM的對象都是使用C++以COM(Component Object Model,組件對象模型)對象的形式實現的,COM對象的垃圾收集策略就是採用引用計數實現的.也就是說,只要在IE中涉及到COM對象,就會存在迴圈引用的問題.

 

請看如下一個示例:

 

 

 

這個示例就是在DOM對象與原生JavaScript對象中間創建了一個迴圈引用.變數obj有一個屬性指向變數div的DOM對象,而變數div也有一個屬性回指obj.由於存在迴圈引用,因此即使將DOM移除,也不會被回收掉.

 

為了避免這種問題,最好是在不使用它們的時候手工斷開它們之間的鏈接,即將它們的值各自設置為null即可.如下圖所示:

 

 

IE9將BOM和DOM都轉換成了真正的JavaScript對象.這樣也就解決了兩種垃圾演算法並存導致的問題,還解決了記憶體泄漏現象.

 

二.性能問題

 

JavaScript垃圾收集器是周期性的運行,,如果為變數分配的記憶體數量很可觀,回收工作量也是相當大的.因此,在這種情況下,確定垃圾收集器的時間間隔也成為了一個重要的問題.

 

IE的垃圾收集器是根據記憶體分配量運行的,具體點說,就是達到256個變數,4096個對象(或數組)字面量和數組元素(slot)或者64kb的字元串,這樣的臨界值,垃圾收集器就會運行.這樣造成的一個問題就是垃圾收集器不得不頻繁的運行,因為一旦一個腳本包含許多變數,該腳本就會在其生命周期內保存許多變數,由此便引發了嚴重的性能問題.

 

IE7的發佈改進了這個問題,它改變了垃圾收集的工作方式.達到臨界值被調整為動態修正,初始值與IE6是一樣的,如果記憶體分配量低於15%,則臨界值就會加倍.如果回收了85%的記憶體分配量,則重置臨界值為預設值.這樣調整大大提升了性能.

 

其實,在有的瀏覽器中可以觸發垃圾收集過程,在IE中,調用window.CollectGarbage()方法可立即執行.在Opera7及更高版本中,調用window.opera.collect()也會啟動垃圾收集常式.

 

三.管理記憶體

 

 儘管開發人員可以不用擔心記憶體管理的問題,在使用具備垃圾收集機制的語言編寫程式.但是JavaScript在進行記憶體管理及垃圾收集時面臨的問題還是有點不同的.其中最主要的一個問題就是分配給web瀏覽器的可用記憶體數量通常要比分配給桌面應用程式的少.

 

這樣的意義在於對安全方面考慮,目的是防止JavaScript的網頁耗盡全部系統記憶體而導致系統崩潰.記憶體限制問題不僅會影響給變數分配記憶體,同時還會影響調用棧以及在一個線程中能夠同時執行的語句數量.

 

所以,確保最少的記憶體可以給頁面帶來更好的性能,優化記憶體最好的方式,就是可以為執行中的代碼保存必要的數據.一旦數據不再有用,那麼最好將其值設置為null來釋放其引用,這個做法也被叫做解除引用.這個做法適合大多數全局變數和全局對象的屬性,當然局部環境的變數會自動解除其引用,所以不必如此做.

 

來看下圖一個示例:

 

 

 

上圖示例,變數o獲取到了函數返回的值,而在createName()函數內部,通過傳入一個參數name,可以賦給局部變數obj的firstname屬性,當函數執行完畢,變數obj就會立即被銷毀,也就是自動解除了引用,但對於變數o而言,因為是全局變數,所以需要我們手動去解除引用,將值設置為null就行了.當然解除一個引用並不是自動回收它占用的記憶體.解除引用的真正作用是讓值脫離執行環境,從而方便垃圾收集器下次運行時回收.


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • java.net.UnknownHostException 錯誤解決方向 1. 查看是否申明瞭網路的許可權。     在AndroidManifest中需要聲明網路許可權 ···java ··· 註意申明許可權的節點不要弄錯。 2. 測試真機或者模擬機是否連上了網路 ...
  • 報錯如圖 解決 在 路徑下,刪除所有文件夾,重新run android ps:網上搜了說是說是java解壓縮編碼格式問題什麼的,感覺不靠譜,自己試出來的,不知道對別人有沒有用。 有問題歡迎交流,謝謝閱讀 ...
  • 前言 早就聽過爬蟲,這幾天開始學習nodejs,寫了個爬蟲 demo ,爬取 博客園首頁的文章標題、用戶名、閱讀數、推薦數和用戶頭像,現做個小總結。 使用到這幾個點: 1、node的核心模塊-- 文件系統 2、用於http請求的第三方模塊 -- superagent 3、用於解析DOM的第三方模塊 ...
  • 思路:通過命令行修改瀏覽器啟動參數,使得瀏覽器不進行跨域檢查,從而允許跨域 方法:命令行參數啟動瀏覽器後添加參數--disable-web-security 例:chrome --disable-web-security --disabl-web-security參數的作用是禁止瀏覽器進行跨域檢查 ...
  • 今天把昨天遺留的問題解決了。 點擊過後終於出現效果了,以後儘量趕在11點睡吧。 大家晚安。 ...
  • 作為一個圍棋愛好者,就決定在博客裡加個圍棋js程式。於是,申請了博客的js許可權,美化美化我的博客。 好在js的語法像C系的,看了看,寫個程式應該還是可以的。 圍棋里,設計好基本的數據結構: 畫圖用canvas,之前並未接觸,一樣,baidu上搜搜,知道了畫圓、畫線、畫方塊的辦法,OK了,我畫圍棋說白 ...
  • 可以用淘寶npm鏡像 然後安裝 然後初始化項目: Watch就是一個監聽 v-if是如果為false就根本不在頁面存在這個元素 v-show是通過display:none來控制這個元素的顯示和隱藏 red表示class名稱,isRed表示是否是bool值來判斷是否顯示red這個class樣式 :cl ...
  • 本文最初發表於 "博客園" ,併在 "GitHub" 上持續更新 前端的系列文章 。歡迎在GitHub上關註我,一起入門和進階前端。 以下是正文。 前言 ECMAScript 是 JS 的語言標準。而 ES6 是新的 JS 語法標準。 PS:嚴格來說,ECMAScript 還包括其他很多語言的語言標 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...