javascript的垃圾收集機制

来源:http://www.cnblogs.com/xiaohuochai/archive/2016/12/08/6145258.html
-Advertisement-
Play Games

[1]原理 [2]標記清除 [3]引用計數 [4]性能問題 [5]記憶體管理 ...


×
目錄
[1]原理 [2]標記清除 [3]引用計數[4]性能問題[5]記憶體管理

前面的話

  javascript具有自動垃圾收集機制,執行環境會負責管理代碼執行過程中使用的記憶體。在編寫javascript程式時,開發人員不用再關心記憶體使用問題,所需記憶體的分配以及無用記憶體的回收完全實現了自動管理。下麵將詳細介紹javascript的垃圾收集機制

 

原理

  垃圾收集機制的原理很簡單:找出那些不再繼續使用的變數,然後釋放其占用的記憶體,垃圾收集器會按照固定的時間間隔,或代碼執行中預定的收集時間,周期性地執行這一操作

  局部變數只在函數執行的過程中存在。而在這個過程中,會為局部變數在棧(或堆)記憶體上分配相應的空間,以便存儲它們的值。然後在函數中使用這些變數,直到函數執行結束。此時,局部變數就沒有存在的必要了。因此可以釋放它們的記憶體以供將來使用。在這種情況下,很容易判斷變數是否還有存在的必要;但並非所有情況下都這麼容易就能得出結論

  垃圾收集器必須跟蹤哪個變數有用哪個變數無用,對於不再有用的變數打上標記,以備將來收回其所占用的記憶體。用於標識無用變數的策略通常有標記清除和引用計數兩種

 

標記清除

  javascript中最常用的垃圾收集方式是標記清除(mark-and-sweep),當變數進入環境(例如,在函數中聲明一個變數),就將這個變數標記為'進入環境'。從邏輯上講,永遠不能釋放進入環境的變數所占用的記憶體,因為只要執行流進入相應的環境,就可能會用到它們。而當變數離開環境時,則將其標記為'離開環境'

  可以用任何方式來標記變數。比如,可以通過翻轉某個特殊的位來記錄一個變數何時進入環境,或者使用一個'進入環境的'變數列表以及一個'離開環境'的變數列表來跟蹤哪個變數發生了變化。說到底,如何標記變數其實並不重要,關鍵在於採取什麼策略

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

  大多數瀏覽器實現使用的都是標記清除式的垃圾收集策略,只不過垃圾收集的時間互有不同

 

引用計數

  另一種不太常見的垃圾收集策略叫做引用計數(reference counting)

  引用計數的含義是跟蹤記錄每個值被引用的次數。當聲明瞭一個變數並將一個引用類型值賦給該變數時,則這個值的引用次數就是1,如果同一個值又被賦給另一個變數,則該值的引用次數加1。相反,如果包含對這個值的引用的變數又取得了另外一個值,則這個值的引用次數減1,當這個值的引用次數為0時,則說明沒有辦法再訪問這個值了,因此就可以將其占用的記憶體空間回收回來。這樣,當垃圾收集器下次再運行時,它就會釋放那些引用次數為0的值所占用的記憶體

  Netscape Navigator3.0是最早使用引用計數策略的瀏覽器,但很快它就遇到了一個嚴重的問題——迴圈引用:對象A中包含一個指向對象B的指針,對象B中也包含一個指向對象A的指針

function problem(){
    var objectA = new Object();
    var objectB = new Object();

    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}

  在這個例子中,objectA和objectB通過各自的屬性相互引用,這兩個對象的引用次數都是2。在採用標記清除策略的實現中,由於函數執行之後,這兩個對象都離開了作用域,因此這種相互引用不是問題。但在採用引用計數策略的實現中,當函數執行完畢之後,objectA和objectB還將繼續存在,因為它們的引用次數永遠不會是0。假如這個函數被重覆多次調用,就會導致大量記憶體得不到回收

  IE中有一部分對象並不是原生javascript對象,例如,其BOM和DOM中的對象就是使用c++以COM(component Object Model 組件對象模型)對象的形式實現,而COM對象的垃圾回收機制採用的就是引用計數策略。因此,即使IE的javascript引擎是使用標記清除策略來實現的,但javascript訪問的COM對象依然是基於引用計數策略的。換句話說,只要在IE中涉及COM對象,就會存在迴圈引用的問題

var element = document.getElementById('some_element');
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

  這個例子在一個DOM元素(element)與一個原生javascript對象(myObject)之間創建了迴圈引用。其中,變數myObject有一個名為element的屬性指向element對象,而變數element也有一個屬性名為someObject的屬性指向myObject。由於存在這個迴圈引用,即使將例子中的DOM從頁面中移除,它也永遠不會被回收

  為了避免類似這樣的迴圈引用,最好是在不使用它們的時候手工斷開原生javascript和DOM元素之間的連接

myObject.element = null;
element.someObject = null; 

  將變數設置為null意味著切斷變數與它此前引用的值之間的連接。當垃圾收集器下次運行時,就會刪除這些值並回收它們占用的記憶體

  為瞭解決此問題,IE9把BOM和DOM對象都轉換成了真正的javascript對象

 

性能問題

  垃圾收集器是周期性運行的,而且如果為變數分配的記憶體數量很可觀,那麼回收工作量也是相當大的。在這種情況下,確定垃圾收集時間間隔是一個非常重要的問題

  IE的垃圾收集器是根據記憶體分配量運行的。具體一點說,就是256個變數,4096個對象(或數組)字面量和數組元素(slot)或者64kb的字元串。達到上述任何一個臨界值,垃圾收集器就會運行

  這種實現方式的問題在於,如果一個腳本中包含那麼多變數,那麼該腳本很可能會在其生命周期中一直保有那麼多的變數。而這樣一來,垃圾收集器就不得不頻繁地運行。結果,由此引發的嚴重性能問題促使IE7重寫了其垃圾收集常式

  IE7的javascript引擎的垃圾收集常式改變了工作方式:觸發垃圾收集的變數分配、字面量和數組元素的臨界值被調整為動態修正。IE7中的各項臨界值在初始時與IE6相等。如果垃圾收集常式回收的記憶體分配量低於15%,則變數、字面量和數組元素的臨界值就會加倍。如果常式回收了85%的記憶體分配量,則將各種臨界值重置回預設值。這樣,極大地提升了IE在運行包含大量javascript的頁面時的性能

  事實上,在有的瀏覽器中可以觸發垃圾收集過程。在IE中,調用window.CollectGarbage()方法會立即執行垃圾收集

 

記憶體管理

  使用具備垃圾收集機制的javascript的主要問題在於:分配給web瀏覽器的可用記憶體數量通常要比分配給桌面應用程式的少,目的是防止運行javascript的網頁耗盡全部系統記憶體而導致系統崩潰。記憶體限制問題不僅會影響給變數分配記憶體,同時還會影響調用棧以及在一個線程中能夠同時執行的語句數量

  因此,確保占用最少的記憶體可以讓頁面獲得更好的性能。而優化記憶體占用的最佳方式是:為執行中的代碼只保存必要的數據。一旦數據不再有用,最好通過將其值設置為null來釋放其引用,這種做法叫解除引用(dereferencing)。這一做法適用於大多數全局變數和全局對象的屬性,局部變數會在它們離開執行環境時自動被解除引用

function createPerson(name){
    var localPerson = new Object();
    localPerson.name = name;
    return localPerson;
}

var globalPerson = createPerson('test');
globalPerson = null;

  不過,要註意的是,解除一個值的引用並不意味著自動回收該值所占用的記憶體。解除引用的真正作用是讓值脫離執行環境,以便垃圾收集器下次運行時將其回收


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

-Advertisement-
Play Games
更多相關文章
  • HTML CSS jQuery 我們先聲明變數,後面的代碼要用到以下變數。 接下來,我們自定義一個函數:getData(),用來獲取當前頁數據。函數中,我們利用$.ajax()向後臺pages.php發送POST非同步請求,將當前頁碼以JSON格式傳遞給後臺。 請求成功後並返回數據,將相應的數據附給變 ...
  • demo:https://zsqosos.github.io/weather/ 截圖: 實現功能:打開網頁時顯示用戶所在城市的天氣狀況,在輸入框輸入城市可查詢其它城市。 實現過程:先調用百度地圖的API來獲取用戶所在的城市,隨後調用聚合數據的天氣API將數據放在頁面上。由於ajax不支持跨域,所以採 ...
  • ng-options="item.action for item in todos" ng-options表達式的基本形式, 形如 "<標簽> for <項目> in <數組> <option value="">(chosse one) </option> ng-options="item.id a ...
  • 如圖,獲取網站中問號後的參數值。 ...
  • 問題很簡單,做個上傳文件的頁面。 html頁面中簡單兩行代碼就完成基本的文件上傳頁面。如下圖。解決。 /***************************分割線********************/ 此時又來了一個新問題:如何獲取用戶上傳的這個文件的文件名、文件大小、文件類型? 效果如下圖。 ...
  • 一、負邊距與浮動佈局 1.1、負邊距 所謂的負邊距就是margin取負值的情況,如margin:-100px,margin:-100%。當一個元素與另一個元素margin取負值時將拉近距離。常見的功能如下: 1.1.1、向上移動 當多個元素同時從標準流中脫離開來時,如果前一個元素的寬度為100%寬度 ...
  • 一、標簽概述 1.HTML(英文Hyper Text Markup Language的縮寫)中文譯為“超文本標簽語言”,主要是通過HTML標簽對網頁中的文本、圖片、聲音等內容進行描述。 2.標簽分為嵌套關係與併列關係。 嵌套關係: 併列關係: 二、基本標簽 1.html標簽:作為整個html中所有標 ...
  • bootstrap框架提供了很多好用的javascript組件,可以很方便的實現常用的js效果,比如點擊彈出一個div(modal)、下拉菜單、旋轉木馬(carousel或slider),非常適合前端不專業的後端程式員使用。下麵就來看下modal和carousel如何使用。 modal即點擊彈出di ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...