(問題一:什麼叫記憶體回收機制?) 記憶體回收是一種動態儲存裝置管理技術,它自動地釋放不再被程式引用的對象,按照特定的垃圾收集演算法來實現資源自動回收的功能。當一個對象不再被引用的時候,記憶體回收它佔領的空間,以便空間被後來的新對象使用,以免造成記憶體泄露。
(問題二:java的記憶體回收有什麼特點?) JAVA語言不允許程式員直接控制記憶體空間的使用。記憶體空間的分配和回收都是由JRE負責在後台自動進行的,尤其是無用記憶體空間的回收操作 (garbagecollection,也稱記憶體回收),只能由運行環境提供的一個超級線程進行監測和控制。
(問題三:記憶體回收行程什麼時候會運行?) 一般是在CPU空閑或空間不足時自動進行記憶體回收,而程式員無法精確控制記憶體回收的時機和順序等。
(問題四:什麼樣的對象符合記憶體回收條件?) 當沒有任何獲得線程能訪問一個對象時,該對象就符合記憶體回收條件。
(問題五:記憶體回收行程是怎樣工作的?) 記憶體回收行程如發現一個對象不能被任何活線程訪問時,他將認為該對象符合刪除條件,就將其加入回收隊列,但不是立即銷毀對象,何時銷毀並釋放記憶體是無法預知的。記憶體回收不能強制執行,然而Java提供了一些方法(如:System.gc()方法),允許你請求JVM執行記憶體回收,而不是要求,虛擬機器會盡其所能滿足請求,但是不能保證JVM從記憶體中刪除所有不用的對象。(該方法我試過了,的確有些時候是釋放不了記憶體的)
(問題六:一個java程式能夠耗盡記憶體嗎?) 可以。垃圾收集系統嘗試在對象不被使用時把他們從記憶體中刪除。然而,如果保持太多活的對象,系統則可能會耗盡記憶體。記憶體回收行程不能保證有足夠的記憶體,只能保證可用記憶體儘可能的得到高效的管理。
(問題七:如何顯示的使對象符合記憶體回收條件?)
(1) Null 參考 :當對象沒有對他可到達引用時,他就符合記憶體回收的條件。也就是說如果沒有對他的引用,刪除對象的引用就可以達到目的,因此我們可以把引用變數設定為 null,來符合記憶體回收的條件。(實際上我對下列的方法差不多都試過,發現記憶體回收不是迅速執行的,它會有一個緩慢的過程。)
Java代碼
StringBuffer sb = new StringBuffer("hello"); System.out.println(sb); sb=null;
(2) 重新為引用變數賦值:可以通過設定引用變數引用另一個對象來解除該引用變數與一個對象間的參考關聯性。
StringBuffer sb1 = new StringBuffer("hello"); StringBuffer sb2 = new StringBuffer("goodbye"); System.out.println(sb1); sb1=sb2;//此時"hello"符合回收條件 StringBuffer sb1 = new StringBuffer("hello");StringBuffer sb2 = new StringBuffer("goodbye");System.out.println(sb1);sb1=sb2;//此時"hello"符合回收條件
(3) 方法內建立的對象:所建立的局部變數僅在該方法的作用期間記憶體在。一旦該方法返回,在這個方法內建立的對象就符合垃圾收集條件。有一種明顯的例外情況,就是方法的返回對象。(如果調用的類終止後,其中的私人變數應該也會被釋放)
public static void main(String[] args) { Date d = getDate(); System.out.println("d = " + d); } private static Date getDate() { Date d2 = new Date(); StringBuffer now = new StringBuffer(d2.toString()); System.out.println(now); return d2; } public static void main(String[] args) { Date d = getDate(); System.out.println("d = " + d);}private static Date getDate() { Date d2 = new Date(); StringBuffer now = new StringBuffer(d2.toString()); System.out.println(now); return d2;}
(4) 隔離引用:這種情況中,被回收的對象仍具有引用,這種情況稱作隔離島。若存在這兩個執行個體,他們互相引用,並且這兩個對象的所有其他引用都刪除,其他任何線程無法訪問這兩個對象中的任意一個。也可以符合記憶體回收條件。
public class Island { Island i; public static void main(String[] args) { Island i2 = new Island(); Island i3 = new Island(); Island i4 = new Island(); i2.i=i3; i3.i=i4; i4.i=i2; i2=null; i3=null; i4=null; } }
(問題八:垃圾收集前進行清理 ------finalize()方法) java提供了一種機制,使你能夠在對象剛要被記憶體回收之前運行一些代碼。這段代碼位於名為finalize()的方法內,所有類從Object類繼承這個方法。由於不能保證記憶體回收行程會刪除某個對象。因此放在finalize()中的代碼無法保證運行。因此建議不要重寫finalize();
Java記憶體釋放心得 .
1 如果一塊記憶體地區能夠重複利用,最好不要申請新的。這個記憶體地區有可能是系統的一個類,自己的一個內部有數組元素,或者能夠放大量資料的結構。
2 最好不要在迴圈裡面申請記憶體,迴圈越大,越壞事。換句話說,申請記憶體頻率別太高。好比一個人每頓吃兩碗飯正好,身體的消化系統可以承受,如果讓他一頓把十頓的都吃掉,不脹死才怪!
3 讓每個執行個體對象的生命週期盡量短一些,尤其是那些要佔用大記憶體的。因為垃圾收集器的演算法優先考慮那些生命週期短的。和多任務作業系統調度進程,分配cpu的原理類似。
4 對一塊大的記憶體的引用層次不要弄得太複雜,垃圾收集器對這種類型的記憶體快收集起來,也是比較麻木的。
5 養成好習慣,不用的對象顯式設定成null。在希望收集層次比較複雜的對象的時候,先將該對象內部儲存的其他引用都置null了,效果會好一些。
6 最後一招,使用弱引用,虛引用。不過,一般出了記憶體問題,都是前5條做得不好,需要用到6的少之又少。