1. 程式人生 > >胡八一及Java(五):java記憶體回收

胡八一及Java(五):java記憶體回收

當一個物件在堆記憶體中執行時,有以下三種狀態:

可達狀態:當一個物件有一個以上的引用變數引用它,程式可以通過引用變數來呼叫物件的屬性和方法。在有向圖中,這就屬於可達。

可恢復狀態:如果一個物件沒有任何變數再引用它,那麼它將先進入可恢復狀態。系統的垃圾回收機制準備回收該物件所佔的記憶體,在回收該物件之前,系統會呼叫可恢復狀態的物件finalize方法進行資源清理,如果系統呼叫該方法讓物件有一個以上的變數重新引用它,則這個物件就會再變成可達狀態,否則變成不可達狀態。

不可達狀態:當物件沒有引用變數引用它時,而且呼叫finalize方法也沒有使其變為可達狀態,則系統將會回收其物件所佔的記憶體空間。

一個物件可以被一個方法的例項變數引用,可以被其它類的類變數引用,也可以被其他物件的例項物件引用。當某個物件被其他類的類變數所引用時,只有當這個類銷燬時,該物件才會進入可銷燬狀態;當某個物件被其他物件引用時,只有這個物件銷燬時或進入不可達狀態時,這個物件才會進入不可達狀態。

java物件物件的引用有四種:強引用、軟引用、弱引用,虛引用

其中我們程式設計經常可以採納的有兩種:強引用、軟引用。

強引用:程式建立一個物件,並把這個物件賦給一個引用變數。這種引用狀態是Java程式設計中最常見的,被強引用的物件絕不會被垃圾回收機制回收,即使記憶體非常緊張,jvm也不會回收這種強引用所引用的物件,所以這也是Java記憶體洩漏的主要原因之一。

(記憶體洩漏:程式執行過程中會不斷地分配記憶體空間,那些不在使用的記憶體空間將會被回收,從而保證系統可以再次使用這些記憶體,如果存在無用的記憶體沒有被回收回來,那就是記憶體洩漏)

軟引用:通過SoftReference類來實現,當系統的空間足夠時,物件不會被回收,當記憶體緊張時,記憶體才會回收物件。

package aaaaa;

import java.lang.ref.SoftReference;

class Person {
	String name;
	int age;
	public Person(String name,int age){
		this.age=age;
		this.name=name;
	}
	public String toString(){
		return "Person[name]:="+name+",   age="+age;
	}
}
public class Test{
	
	public static void main(String args[]) throws Exception{
     SoftReference<Person>[] people =new SoftReference[100000];	
     for(int i =0;i<people.length;i++){
    	 people[i] =new SoftReference<Person>(new Person("名字"+i,(i+1)*4%100));
     }
     System.out.println(people[2].get());
     System.out.println(people[4].get());
     //通知系統進行垃圾回收
     System.gc();
     System.runFinalization();
     //垃圾回收機制執行會,
     System.out.println(people[2].get());
     System.out.println(people[4].get());
	}
}

執行結果:

Person[name]:=名字2,   age=12
Person[name]:=名字4,   age=20
Person[name]:=名字2,   age=12
Person[name]:=名字4,   age=20

此時記憶體沒有達到緊張狀態,所以沒有清除2和4物件,可通過在cmd中為JVM指定較小的堆記憶體來達到效果,如下

java -Xmx2m  -Xms2m 類名

Java記憶體管理小技巧:

1、儘量使用直接量

當使用字串,Byte,Short,Integer,Float,Double,Boolean,Character包裝類的例項時不應該使用new來建立物件,而應該直接

使用

如:

String a = new String("hello");

這種方式會建立一個“hello"字串,而且JVM的字元緩衝池會快取這個字串,除此之外,a所引用的String物件底層還包含一個char陣列,char數組裡依次存放了hello 的每個字元。

String a ="hello";

而這種就不會產生char陣列。

2、使用StrinBuilder和StringBuffer來進行字串連線

String 代表字元序列不可變字串,而StringBuffer和StringBuilder代表字元序列可變字串。

如果使用String字串來連線字串,則會產生大量零時字串。

3、儘早釋放無用物件,將物件顯式的設定為null

public void info(){
Object obj =new Object();
System.out.println(obj.toString());
System.out.println(obj.hashCode());
obj =null;

//下面是一些耗記憶體的操作,完全需要釋放上面物件的記憶體空間

....
}

4、儘量少用靜態變數

靜態變數生命週期與類同步,當遇到常駐記憶體的class ,一旦被建立,就會常駐記憶體。

5、避免在經常呼叫的方法中,迴圈中建立Java物件

6、快取經常使用的物件

7、儘量不要使用finalize方法

8、考慮使用SoftReference