摘要:垃圾回收器追蹤所有正在使用的對象,將無用對象標記為垃圾。自動化指針內存回收自動化的最好方式之一是使用鉤子函數。它們可能因為多種原因發生,但是這種垃圾回收器是最主流的一種。
原文出處:What Is Garbage Collection?
一眼就應該從名稱看出垃圾回收機制的含義-查找垃圾,然后丟棄。事實正好相反。垃圾回收器追蹤所有正在使用的對象,將無用對象標記為垃圾。請留意,我們開始研究JVM的“Garbage Collection”的實現細節。
避免倉促進入細節,我們因該從入門開始入手。理解垃圾收集器的一般規律,核心、概念,處理方法。
鄭重聲明:本文關注的是Oracle的Hotspot和OpenJDK。其他運行環境或者其他的JVM,諸如jRockit,IBM J9、以及本手冊提及的一些產品會有一些差異化。
內存管理指南
在我們開始講解垃圾回收器的工作方式之前,你需要手動為你的數據分配一塊可用空間。如果你忘記分配,你將不能重復使用這塊空間。這塊空間將被聲明但是不能被使用。例如,內存泄漏。
下面是一個用C實現的簡單內存管理使用示例:
int send_request() { size_t n = read_size(); int *elements = malloc(n * sizeof(int)); if(read_elements(n, elements) < n) { // elements not freed! return -1; } // … free(elements) return 0; }
正如您看到的,它非常容易忘記去釋放內存。內存泄漏是一個比現在更加廣泛的共性問題。你只能把內嵌在你的代碼來克服這個問題。因此,最好的方法是自動回收不用的內存,以完全避免人為錯誤。例如Garbage Collection(GC)自動化操作。
自動化指針
內存回收自動化的最好方式之一是使用鉤子函數。例如,在C++中我們使用vector做同樣的事情,當數據在作用域不再使用時被自動調用的一種鉤子函數:
int send_request() { size_t n = read_size(); vectorelements = vector (n); if(read_elements(elements.size(), &elements[0]) < n) { return -1; } return 0; }
但是多數情況下更加復雜,特別是對象被多個線程跨線程共享,僅僅使用鉤子函數不合適,由此產生最簡單的垃圾回收機制:引用計數。對于每一個對象,只要簡單知道它被引用了多少次,當計數器歸零的時候,它就被安全回收。下面是C++共享指針的著名例子:
int send_request() { size_t n = read_size(); auto elements = make_shared>(); // read elements store_in_cache(elements); // process elements further return 0; }
現在,為了避免元素在下一時刻被其他函數調用,我們也許應該將它們緩存起來。在這種情況下,我們不能選擇當它出了作用域就銷毀vector。因此,我們使用shared_ptr。它記錄引用次數。在它的作用域內數量增加,在作用域之外次數減少。一旦引用次數歸零,shared_ptr 自動刪除其下的vector。
內存自動管理
從上面的C++代碼可以看出,我們依然明確提出關注內存管理。但是如果使用這種方式管理所有的內存有會怎樣呢?它變得非常方便,自此開發人員不再考慮自己手動清除。運行環境會自動識別不再使用的內存并且釋放它。換句話說,它自動回收垃圾。世界上第一款垃圾收集于1959年使用Lisp語言實現,自此相關技術開始向前發展。
引用計數
上文提到我們使用C++共享指針的方式管理所有對象。許多語言,例如 Perl, Python ,PHP都采用這種方式。下圖很好說明了這種方法:
綠色云狀圖標指向的對象說明他們仍然被程序占用。技術上,他們類似于當前執行方法的本地變量或者靜態變量或者其他。不同語言之間的差別很大,本文不做關注。
藍色圖標表示內存中存活的對象,里面的數字代表它們被引用的次數。最后,灰色圖標表示沒有被任何存活對象引用(就是直接被綠色云狀代表對象引用的對象)。灰色對象就這樣被當成垃圾,被垃圾收集器清除。
這看起來很不錯,不是嗎?好吧,的確,但是這種方式存在一個巨大的缺點。這些沒有在作用域中對象發生環狀引用,由于環狀引用導致他們的引用計數不歸零。下面是示意圖:
看到了嗎?實際上,紅色對象沒有被應用程序使用而成為垃圾。由于引用計數的局限性,他們造成了內存泄漏。
有幾種方法客服這種情況,例如使用特殊的“”weak“”引用,或者為了環狀應用特殊的算法。Perl, Python ,PHP使用哪種方式處理,不在本文的討論范圍之內。相反,我開始討論更多JVM的實現細節。
標記清除
首先,對于可達對象,JVM有著明確的定義。與上面章節中綠色云狀圖模糊定義不同的是,我們有一個叫做Garbage Collection Roots(GC Root)的明確定義:
局部變量
活躍線程
靜態域
JNI引用
JVM使用這種方式追蹤所有可達(存活)的對象,通過被稱作標記清除算法重復掃描確定不可達對象。該算法包含兩步:
標記,掃描所有的可達對象,在本地內存這些對象的副本。
清除,確保所有被不可達對象占據的內存空間可以在下一次重新分配。
JVM中多種不同的算法,例如Parallel Scavenge,Parallel Mark+Copy,CMS,他們的實施階段不盡相同,但是執行步驟和上面描述的兩步類似。
這些算法很重要的一點是保證環形引用不再泄漏:
不太好的一點是,回收操作發生的時候,所有的應用線程被停止。正如它們一直在改變引用導致無法準確計算它們的應用的那樣。像這種應用線程被暫時停止,以便JVM活動的晴空稱之為“”stop-the-world“”。它們可能因為多種原因發生,但是這種垃圾回收器是最主流的一種。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66334.html
摘要:正好最近在學習的各種實現原理,在這里斗膽翻譯一篇垃圾回收機制原文鏈接。自動管理的機制中,通常都會包含垃圾回收機制。二垃圾回收機制的概念垃圾回收,是一種自動管理應用程序所占內存的機制,簡稱方便起見,本文均采用此簡寫。 最近關注了一個國外技術博客RisingStack里面有很多高質量,且對新手也很friendly的文章。正好最近在學習Node.js的各種實現原理,在這里斗膽翻譯一篇Node...
摘要:原文出處垃圾回收機制標記清除算法介紹最主要的理論算法之一,在實踐過程中,為了真實情景需要,需要許多調整。因此不會僅僅標記清除,垃圾回收期間,內存整理進程同時在工作。不同內存區域的垃圾收集機制不辣么容易理解。 原文出處:java垃圾回收機制 標記清除算法介紹最主要的理論算法之一,在實踐過程中,為了真實情景需要,需要許多調整。舉一個簡單例子,我們檢查JVM需要做的各種事情,以便我們安全地去...
摘要:原文出處這種垃圾收集器的官方名稱是。使用收集器的名稱。事件時長記錄不同的類型回收期間垃圾收集器線程消耗事件調用操作系統活著等待系統事件消耗時間應用停頓的時鐘時間。現在我們看一些一些任務的時間,垃圾收集器線程等待很長時間。 原文出處:Concurrent Mark and Sweep 這種垃圾收集器的官方名稱是Mostly Concurrent Mark and Sweep Garbag...
摘要:本文將會深入分析的引擎的內部實現。該引擎使用在谷歌瀏覽器內部。同其他現代引擎如或所做的一樣,通過實現即時編譯器在執行時將代碼編譯成機器代碼。這可使正常執行期間只發生相當短的暫停。 原文 How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code 幾周前我們開始了一個系列博文旨在深入...
閱讀 1770·2021-10-11 10:59
閱讀 2412·2021-09-30 09:53
閱讀 1770·2021-09-22 15:28
閱讀 2802·2019-08-29 15:29
閱讀 1563·2019-08-29 13:53
閱讀 3212·2019-08-29 12:34
閱讀 2861·2019-08-26 10:16
閱讀 2668·2019-08-23 15:16