垃圾回收的標記清除演算法詳解
JavaScript有內建的垃圾回收機制,可以使我們免去考慮記憶體分配和釋放的操作問題,從而可以花費更多的精力去完成功能的實現。但是對於它的瞭解還是必不可少的,以便寫出更為優化的程式碼。
當前最基本的垃圾回收演算法有四種:
(1).標記-清除演算法(mark-sweep)。
(2).標記-壓縮演算法(mark-compact)。
(3).複製演算法(copying)。
(4).引用計數演算法(reference counting)。
當前瀏覽器的垃圾回收機制通常是由上述幾種演算法混合而成,本章節就單獨介紹比較流行的標記清除演算法。
一.基本概念:
在垃圾回收的演算法中,經常會出現mutator和collector兩個名稱,下面就對它做一下簡單介紹。
(1).collector:指的就是垃圾收集器。
(2).mutator:指的是垃圾收集器之外的部分,比如當前的應用程式。它的功能是建立新物件,或者在記憶體讀寫內容。
(3).mutator roots:mutator根物件,通常是分配在堆記憶體之外,可以直接被mutator直接訪問到的物件,一般是指靜態/全域性變數。
(4).可到達物件:所謂的可到達物件就是從根物件開始遍歷,可以訪問到的物件,也就是mutator(應用程式)正在使用的物件。
二.演算法原理:
標記清除演算法從名稱上看,可以拆分為兩部分:標記(mark)和清除(sweep)。
此演算法可以分為兩個階段,一個是標記階段,一個是清除階段,下面就分別做一下介紹。
(1).標記階段:
在此階段,垃圾回收器會從mutator(應用程式)根物件開始遍歷。
每一個可以從根物件訪問到的物件都會被新增一個標識,於是這個物件就被標識為可到達物件。
(2).清除階段:
在此階段中,垃圾回收器,會對堆記憶體從頭到尾進行線性遍歷,如果發現有物件沒有被標識為可到達物件,那麼就將此物件佔用的記憶體回收,並且將原來標記為可到達物件的標識清除,以便進行下一次垃圾回收操作。
圖示如下:
在標記階段,從跟對想1可以訪問到B,從B又可以訪問到E,那麼B和E都是可到達物件,同樣的道理,F、G、J和K都是可到達物件。在回收階段,所有未標記為可到達的物件都會被垃圾回收器回收。
特別說明:在垃圾回收階段,應用程式的執行會暫停,等待回收執行完畢後,再恢復程式的執行。
三.何時開始垃圾回收:
在使用標記清除演算法時,未引用物件並不會被立即回收.取而代之的做法是,垃圾物件將一直累計到記憶體耗盡為止.當記憶體耗盡時,程式將會被掛起,垃圾回收開始執行。
四.垃圾回收虛擬碼表示:
[JavaScript] 純文字檢視 複製程式碼New(): //分配新的記憶體到ref指標 ref <- allocate() if ref == null //記憶體不足,則觸發垃圾收集 collect() ref <- allocate() if ref == null //垃圾收集後仍然記憶體不足,則丟擲Out of Memory錯誤 throw "Out of Memory" return ref atomic collect(): markFromRoots() sweep(HeapStart,HeapEnd)
上面的程式碼表示了垃圾回收是如何被觸發的。
[JavaScript] 純文字檢視 複製程式碼markFromRoots(): worklist <- empty //遍歷所有mutator根物件 for each fld in Roots ref <- *fld //如果它是可達的而且沒有被標記的,直接標記該物件並將其加到worklist中 if ref != null && isNotMarked(ref) setMarked(ref) add(worklist,ref) mark() mark(): while not isEmpty(worklist) //將worklist的最後一個元素彈出,賦值給ref ref <- remove(worklist) //遍歷ref物件的所有指標域,如果其指標域(child)是可達的,直接標記其為可達物件並且將其加入worklist中 for each fld in Pointers(ref) //通過這樣的方式來實現深度遍歷,直到將該物件下面所有可以訪問到的物件都標記為可達物件。 child <- *fld if child != null && isNotMarked(child) setMarked(child) add(worklist,child)
上面的是mark標記的演算法。
[JavaScript] 純文字檢視 複製程式碼sweep(start,end): scan <- start while scan < end if isMarked(scan) setUnMarked(scan) else free(scan) scan <- nextObject(scan)
上面的程式碼表示的是垃圾回收的sweep階段。
五.標記清除演算法的缺點:
垃圾收集後有可能會造成大量的記憶體碎片,像上面的圖片所示,垃圾收集後記憶體中存在三個記憶體碎片,假設一個方格代表1個單位的記憶體,如果有一個物件需要佔用3個記憶體單位的話,那麼就會導致Mutator一直處於暫停狀態,而Collector一直在嘗試進行垃圾收集,直到Out of Memory。
相關文章
- 垃圾回收演算法|GC標記-清除演算法演算法GC
- Golang 垃圾回收-三色標記清除演算法Golang演算法
- 《垃圾回收的演算法與實現》第2章GC標記-清除演算法演算法GC
- Java虛擬機器-GC垃圾回收演算法-標記清除法、複製演算法、標記壓縮法、分代演算法Java虛擬機GC演算法
- 垃圾回收的引用計數器演算法詳解演算法
- golang 垃圾回收器如何標記記憶體?Golang記憶體
- JVM 垃圾回收演算法和垃圾回收器JVM演算法
- JVM垃圾回收之三色標記JVM
- C#垃圾回收機制詳解C#
- 12.垃圾收集底層演算法--三色標記詳解演算法
- JVM之垃圾回收機制詳解分析JVM
- JVM垃圾回收演算法JVM演算法
- Java虛擬機器詳解(三)------垃圾回收Java虛擬機
- 物件回收判定與垃圾回收演算法-JVM學習筆記(1)物件演算法JVM筆記
- Java垃圾回收機制詳解及效能最佳化詳解。Java
- javascript 垃圾回收演算法瞭解一下JavaScript演算法
- 垃圾回收(一)【垃圾回收的基礎】
- 淺談垃圾回收演算法演算法
- JVM(九):垃圾回收演算法JVM演算法
- JVM記憶體分配策略,及垃圾回收演算法JVM記憶體演算法
- 垃圾回收(三)【垃圾回收通知】
- 超詳細的node垃圾回收機制
- 垃圾回收之三色標記法(Tri-color Marking)
- jdk8:垃圾回收演算法JDK演算法
- jvm有哪些垃圾回收演算法JVM演算法
- java垃圾回收有哪些演算法Java演算法
- 【JVM】垃圾回收的四大演算法JVM演算法
- 十、jvm垃圾回收演算法、垃圾收集器、引用你真的瞭解麼?JVM演算法
- 學習八、JavaScript的記憶體管理及垃圾回收(GC演算法)JavaScript記憶體GC演算法
- 探索JVM的垃圾回收(堆記憶體)JVM記憶體
- JS垃圾回收機制筆記JS筆記
- 六種主要的垃圾回收演算法和思想演算法
- 垃圾回收演算法:引用計數法演算法
- JVM系列(五) - JVM垃圾回收演算法JVM演算法
- JVM調優:基本垃圾回收演算法JVM演算法
- JVM垃圾回收器、記憶體分配與回收策略JVM記憶體
- 垃圾回收
- 圖解Golang垃圾回收機制!圖解Golang