Java垃圾回收機制通常包含近十種算法。對這些算法中的多數,咱們沒必要予以關心。只有其中最簡單的一個:引用計數法,與編碼有關。算法
一.誰在作Garbage Collection?函數
在C++裏,釋放內存是手動處理的,要用delete運算符來釋放分配的內存。這是流行的說法。確切地說,是應用認爲不須要某實體時,就需用delete告訴系統,能夠回收這塊空間了。這個要求,對編碼者來講,是件很麻煩、很難作到的事。隨便上哪一個BBS,在C/C++版塊里老是有一大堆關於內存泄漏的話題。編碼
Java採用一種不一樣的,很方便的方法:Garbage Collection。Java垃圾回收機制放在JVM裏。JVM徹底負責垃圾回收事宜,應用只在須要時申請空間,而在拋棄對象時沒必要關心空間回收問題。spa
二.對象在啥時被丟棄?code
在C++裏,當對象離開其做用域時,該對象即被應用拋棄。對象
是對象的生命期再也不與其做用域有關,而僅僅與引用有關。進程
Java的垃圾回收機制通常包含近十種算法。對這些算法中的多數,咱們沒必要予以關心。只有其中最簡單的一個:引用計數法,與編碼有關。內存
一個對象,能夠有一個或多個引用變量指向它。當一個對象再也不有任何一個引用變量指向它時,這個對象就被應用拋棄了。或者說,這個對象能夠被垃圾回收機制回收了。作用域
這就是說,當不存在對某對象的任何引用時,就意味着,應用告訴JVM:我不要這個對象,你能夠回收了。字符串
JVM的垃圾回收機制對堆空間作實時檢測。當發現某對象的引用計數爲0時,就將該對象列入待回收列表中。可是,並非立刻予以銷燬。
三.丟棄就被回收?
該對象被認定爲沒有存在的必要了,那麼它所佔用的內存就能夠被釋放。被回收的內存能夠用於後續的再分配。
可是,並非對象被拋棄後立即被回收的。JVM進程作空間回收有較大的系統開銷。若是每當某應用進程丟棄一個對象,就當即回收它的空間,勢必會使整個系統的運轉效率很是低下。
前面說過,JVM的垃圾回收機制有多個算法。除了引用計數法是用來判斷對象是否已被拋棄外,其它算法是用來肯定什麼時候及如何作回收。JVM的垃圾回收機制要在時間和空間之間作個平衡。
所以,爲了提升系統效率,垃圾回收器一般只在知足兩個條件時才運行:即有對象要回收且系統須要回收。切記垃圾回收要佔用時間,所以,Java運行時系統只在須要的時候才使用它。所以你沒法知道垃圾回收發生的精確時間。
四.沒有引用變量指向的對象有用嗎?
前面說了,沒掛上引用變量的對象是被應用丟棄的,這意味着,它在堆空間裏是個垃圾,隨時可能被JVM回收。
不過,這裏有個不是例外的例外。對於一次性使用的對象(有些書稱之爲臨時對象),能夠不用引用變量指向它。舉個最簡單也最多見的例子:
System.out.println(「I am Java!」);
就是建立了一個字符串對象後,直接傳遞給println()方法。
五.應用能干預垃圾回收嗎?
許多人對Java的垃圾回收機制不放心,但願在應用代碼裏控制JVM的垃圾回收運做。這是不可能的事。對垃圾回收機制來講,應用只有兩個途徑發消息給JVM。第一個前面已經說了,就是將指向某對象的全部引用變量所有移走。這就至關於向JVM發了一個消息:這個對象不要了。第二個是調用庫方法System.gc(),多數書裏說調用它讓Java作垃圾回收。
第一個是一個告知,而調用System.gc()也僅僅是一個請求。JVM接受這個消息後,並非當即作垃圾回收,而只是對幾個垃圾回收算法作了加權,使垃圾回收操做容易發生,或提前發生,或回收較多而已。
但願JVM及時回收垃圾,是一種需求。其實,還有相反的一種須要:在某段時間內最好不要回收垃圾。要求運行速度最快的實時系統,特別是嵌入式系統,每每但願如此。
Java的垃圾回收機制是爲全部Java應用進程服務的,而不是爲某個特定的進程服務的。所以,任何一個進程都不能命令Java垃圾回收機制作什麼、怎麼作或作多少。
六.對象被回收時要作的事
一個對象在運行時,可能會有一些東西與其關連。所以,當對象即將被銷燬時,有時須要作一些善後工做。能夠把這些操做寫在finalize()方法(常稱之爲終止器)裏。
protected void finalize()
{
// finalization code here
}
這個終止器的用途相似於C++裏的析構函數,並且都是自動調用的。可是,二者的調用時機不同,使二者的表現行爲有重大區別。C++的析構函數老是當對象離開做用域時被調用。這就是說,C++析構函數的調用時機是肯定的,且是可被應用判知的。可是,Java終止器倒是在對象被銷燬時。由上所知,被丟棄的對象什麼時候被銷燬,應用是沒法獲知的。並且,對於大多數場合,被丟棄對象在應用終止後仍未銷燬。
在編碼時,考慮到這一點。譬如,某對象在運做時打開了某個文件,在對象被丟棄時不關閉它,而是把文件關閉語句寫在終止器裏。這樣作對文件操做會形成問題。若是文件是獨佔打開的,則其它對象將沒法訪問這個文件。若是文件是共享打開的,則另外一訪問該文件的對象直至應用終結仍不能讀到被丟棄對象寫入該文件的新內容。
至少對於文件操做,編碼者應認清Java終止器與C++析構函數之間的差別。
那麼,當應用終止,會不會執行應用中的全部finalize()呢?據Bruce Eckel在Thinking in Java裏的觀點:「到程序結束的時候,並不是全部收尾模塊都會獲得調用」。這還僅僅是指應用正常終止的場合,非正常終止呢?
所以,哪些收尾操做能夠放在finalize()裏,是須要酌酎的。