java垃圾回收機制

java 語言中一個顯著的特點就是引入了java回收機制,是c++程序員最頭疼的內存管理的問題迎刃而解,它使得java程序員在編寫程序的時候不在考慮內存管理。由於有個垃圾回收機制,java中的額對象不在有“作用域”的概念,只有對象的引用纔有“作用域”。垃圾回收可以有效的防止內存泄露,有效的使用空閒的內存,以下是小編爲大家搜索整理java垃圾回收機制,希望能給大家帶來幫助!更多精彩內容請及時關注我們應屆畢業生考試網!

java垃圾回收機制

  手動管理內存

在介紹現代版的垃圾回收之前,我們先來簡單地回顧下需要手動地顯式分配及釋放內存的那些日子。如果你忘了去釋放內存,那麼這塊內存就無法重用了。這塊內存被佔有了卻沒被使用。這種場景被稱之爲內存泄露。

下面是用C寫的一個手動管理內存的簡單例子:

14int 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;}

可以看到,你很容易就會忘了釋放內存。內存泄露曾經是個非常普遍的問題。你只能通過不斷地修復自己的代碼來與它們進行抗爭。因此,需要有一種更優雅的方式來自動釋放無用內存,以便減少人爲錯誤的可能性。這種自動化過程又被稱爲垃圾回收(簡稱GC)。

  智能指針

自動垃圾回收早期的`一種實現便是引用計數。你知曉每一個對象被引用了幾次,當計數器歸0的時候,這個對象就可以被安全地回收掉了。C++的共享指針就是一個非常着名的例子:

11int send_request() { size_t n = read_size(); stared_ptrelements = make_shared(); if(read_elements(n, elements) < n) { return -1; } return 0;}

我們使用的sharedptr會記錄這個對象被引用的次數。如果你將它傳遞給別人則計數加一,當它離開了作用域後便會減一。一旦這個計數爲0,sharedptr會自動地刪除底層對應的vector。當然這只是個示例,因爲也有讀者指出來了,這個在現實中是不太可能出現的,但作爲演示是足夠了。

  自動內存管理

在上面的C++代碼中,我們還得顯式地聲明我們需要使用內存管理。那如果所有的對象都採用這個機制會怎樣呢?那簡直就太方便了,這樣開發人員便無需 考慮清理內存的事情了。運行時會自動知曉哪些內存不再使用了,然後釋放掉它。也就是說,它自動地回收了這些垃圾。第一代的垃圾回收器是1959年Lisp 引入的,這項技術迄今爲止一直在不斷演進。

  引用計數

剛纔我們用C++的共享指針所演示的想法可以應用到所有的對象上來。許多語言比如說Perl, Python以及PHP,採用的都是這種方式。這個通過一張圖可以很容易說明:

綠色的雲代表的是程序中仍在使用的對象。從技術層面上來說,這有點像是正在執行的某個方法裏面的局部變量,亦或是靜態變量之類的。不同編程語言的情況可能會不一樣,因此這並不是我們關注的重點。

藍色的圓圈代表的是內存中的對象,可以看到有多少對象引用了它們。灰色圓圈的對象是已經沒有任何人引用的了。因此,它們屬於垃圾對象,可以被垃圾回收器清理掉。

看起來還不錯對吧?沒錯,不過這裏存在着一個重大的缺陷。很容易會出現一些孤立的環,它們中的對象都不在任何域內,但彼此卻互相引用導致引用數不爲0。下面便是一個例子:

看到了吧,紅色部分其實就是應用程序不再使用的垃圾對象。由於引用計數的缺陷,因此會存在內存泄露。

有幾種方法可以解決這一問題,比如說使用特殊的“弱”引用,或者使用一個特殊的算法回收循環引用。之前提到的Perl,Python以及PHP等語言,都是使用類似的方法來回收循環引用的,不過這已經超出本文講述的範圍了。我們準備詳細介紹下JVM所採用的方法。

  標記刪除

首先,JVM對於對象可達性的定義要明確一些。它可不像前面那樣用綠色的雲便含煳了事的,而是有着非常明確及具體的垃圾回收根對象(Garbage Collection Roots)的定義:

局部變量

活動線程

靜態字段

JNI引用

  其它(後面將會討論到)

JVM通過標記刪除的算法來記錄所有可達(存活)對象,同時確保不可達對象的那些內存能夠被重用。這包含兩個步驟:

標記是指遍歷所有可達對象,然後在本地內存中記錄這些對象的信息

刪除會確保不可達對象的內存地址可以在下一次內存分配中使用。

JVM中的不同GC算法,比如說Parallel Scavenge,Parallel Mark+Copy, CMS都是這一算法的不同實現,只是各階段略有不同而已,從概念上來講仍然是對應着上面所說的那兩個步驟。

這種實現最重要的就是不會再出現泄露的對象環了:

缺點就是應用程序的線程需要被暫停才能完成回收,如果引用一直在變的話你是無法進行計數的。這個應用程序被暫停以便JVM可以收拾家務的情況又被稱爲Stop The World pause(STW)。這種暫停被觸發的可能性有很多,不過垃圾回收應該是最常見的一種。