Js具有自動垃圾回收機制。垃圾收集器會按照固定的時間間隔周期性的執行。 JS中最常見的垃圾回收方式是標記清除。 工作原理:是當變數進入環境時,將這個變數標記為“進入環境”。當變數離開環境時,則將其標記為“離開環境”。標記“離開環境”的就回收記憶體。 工作流程: 1. 垃圾回收器,在運行的時候會給存儲在 ...
Js具有自動垃圾回收機制。垃圾收集器會按照固定的時間間隔周期性的執行。
JS中最常見的垃圾回收方式是標記清除。
工作原理:是當變數進入環境時,將這個變數標記為“進入環境”。當變數離開環境時,則將其標記為“離開環境”。標記“離開環境”的就回收記憶體。
工作流程:
1. 垃圾回收器,在運行的時候會給存儲在記憶體中的所有變數都加上標記。
2. 去掉環境中的變數以及被環境中的變數引用的變數的標記。
3. 再被加上標記的會被視為準備刪除的變數。
4. 垃圾回收器完成記憶體清除工作,銷毀那些帶標記的值並回收他們所占用的記憶體空間。
引用計數 方式
工作原理:跟蹤記錄每個值被引用的次數。
工作流程:
1. 聲明瞭一個變數並將一個引用類型的值賦值給這個變數,這個引用類型值的引用次數就是1。
2. 同一個值又被賦值給另一個變數,這個引用類型值的引用次數加1.
3. 當包含這個引用類型值的變數又被賦值成另一個值了,那麼這個引用類型值的引用次數減1.
4. 當引用次數變成0時,說明沒辦法訪問這個值了。
5. 當垃圾收集器下一次運行時,它就會釋放引用次數是0的值所占的記憶體。
但是迴圈引用的時候就會釋放不掉記憶體。迴圈引用就是對象A中包含另一個指向對象B的指針,B中也包含一個指向A的引用。
因為IE中的BOM、DOM的實現使用了COM,而COM對象使用的垃圾收集機制是引用計數策略。所以會存在迴圈引用的問題。
解決:手工斷開js對象和DOM之間的鏈接。賦值為null。IE9把DOM和BOM轉換成真正的JS對象了,所以避免了這個問題。
什麼情況會引起記憶體泄漏?
雖然有垃圾回收機制但是我們編寫代碼操作不當還是會造成記憶體泄漏。
1. 意外的全局變數引起的記憶體泄漏。
原因:全局變數,不會被回收。
解決:使用嚴格模式避免。
2. 閉包引起的記憶體泄漏
原因:閉包可以維持函數內局部變數,使其得不到釋放。
解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用。
3. 沒有清理的DOM元素引用
原因:雖然別的地方刪除了,但是對象中還存在對dom的引用
解決:手動刪除。
4. 被遺忘的定時器或者回調
原因:定時器中有dom的引用,即使dom刪除了,但是定時器還在,所以記憶體中還是有這個dom。
解決:手動刪除定時器和dom。
5. 子元素存在引用引起的記憶體泄漏
原因:div中的ul li 得到這個div,會間接引用某個得到的li,那麼此時因為div間接引用li,即使li被清空,也還是在記憶體中,並且只要li不被刪除,他的父元素都不會被刪除。
解決:手動刪除清空。
什麼放在記憶體中?什麼不放在記憶體中?
基本類型是:Undefined/Null/Boolean/Number/String
基本類型的值存在記憶體中,被保存在棧記憶體中。從一個變數向另一個變數複製基本類型的值,會創建這個值的一個副本。
引用類型:object
引用類型的值是對象,保存在堆記憶體中。
1. 包含引用類型值的變數實際上包含的並不是對象本身,而是一個指向該對象的指針。從一個變數向另一個變數複製引用類型的值,複製的其實是指針,因此兩個變數最終都指向同一個對象。
2. js不允許直接訪問記憶體中的位置,也就是不能直接訪問操作對象的記憶體空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。
棧和堆的區別
一、堆棧空間分配區別:
1、棧(操作系統):由操作系統自動分配釋放 ,存放函數的參數值,局部變數的值等。其操作方式類似於數據結構中的棧;
2、堆(操作系統): 一般由程式員分配釋放,若程式員不釋放,程式結束時可能由OS回收,分配方式倒是類似於鏈表。
二、堆棧緩存方式區別:
1、棧使用的是一級緩存, 他們通常都是被調用時處於存儲空間中,調用完畢立即釋放;
2、堆是存放在二級緩存中,生命周期由虛擬機的垃圾回收演算法來決定(並不是一旦成為孤兒對象就能被回收)。所以調用這些對象的速度要相對來得低一些。
三、堆棧數據結構區別:
堆(數據結構):堆可以被看成是一棵樹,如:堆排序;
棧(數據結構):一種先進後出的數據結構。