Java內存管理的技巧

掌握Java的內存回收、垃圾回收機制是爲了更好地管理Java虛擬機內存,這樣能夠好的提高Java程序的運行效率。下面總結幾個內存管理的小技巧,希望時刻提醒自己的編程習慣。

1、避免在經常調用的方法、循環中創建Java對象

先看下面代碼:

public class test2 {
	public static void main(String[] args) {
		List<String> list1 = new ArrayList<String>();
		//此處略去list1的初始化過程......
		List<String> list2 = new ArrayList<String>();
		for (String src : list1) {
			String str = src;
			list2.add(str);
		}
		//此處略去後續操作
	}
}
從上面的代碼中可以看到,循環多少次就創建多少個str對象。雖然str對象是局部的,當循環執行結束str會自動被回收,但是這會導致兩點不足:

1)java內存緊張,在循環還沒有退出的時候就拋出java.lang.OutOfMemoryError: Java heap space ,即java內存溢出。

2)str對象生命週期非常短,循環退出之後GC會自動回收str對象們所佔用的內存空間,這種不斷的分配、回收操作中,程序性能受到巨大的影響。

建議:儘量不要在循環內創建java對象。

2、儘量使用直接量

當使用字符串,或者包裝類(如Byte,Integer,Long,Boolean等)的實例時候,程序不應該用new的方式創建對象,最好採用直接量來創建它們。例如:

String str="hello";
這種方式會創建“hello”字符串,而且JVM的常量緩存池會緩存這個字符串。

如果程序使用如下代碼:

String str=new String("hello");
此時,程序創建了一個“hello”字符串,除此之外,str所引用的對象的底層還包含了一個cha[]數組,依次存放了h、e、l、l、o字符。

但是,應該注意,當str經常地變化時候,應該避免使用,因爲常量池中緩存的字符串失去引用後不會被GC回收。
3、使用StringBuilder和StringBuffer進行字符串的連接

String,StringBuilder,StringBuffer都代表字符串,但是String代表的字符串序列是不可變的,而後兩者是可變的。

如果程序需要使用多個String對象進行字符串連接操作,在運行時候會產生大量的臨時字符串,這些字符串保存在內存中不被回收,從而導致程序性能下降。例如:

String str="hello";//此處生成一個"hello"對象存在常量池中
str+=" world";//此處又重新生成了"hello world"這個新對象存在常量池中,上面的"hello"失去引用,但在常量池中不會被回收

而StringBuilder和StringBuffer由於是可變的,都是在當前字符串基礎上修改,因此不會生成大量無用的中間量。

4、儘量少用靜態變量

GC在進行垃圾回收的時候判斷一個對象是否是垃圾的唯一標準就是該對象是否有引用變量引用它,因此推薦儘量早的釋放對象的引用。但是static變量恰恰是最壞的情況,靜態變量屬於整個類,它的生命週期與類相同,因此在類不卸載的情況下,靜態變量就會常駐內存,直至程序運行結束。

5、儘量早的釋放無用對象的引用

如果在某對象obj之後執行耗時,耗內存的操作,而且對象obj已經不會使用,那麼儘量在耗時,耗內存的操作之前就將obj置空(obj=null;),這樣可能的情況就是:當程序在執行耗時耗內存的操作時,GC會對obj所引用的對象進行垃圾回收。

6、緩存經常使用到的對象

如果有些對象經常被使用到,可以考慮把這些對象用緩存池保存起來,這樣下次使用的時候就可以直接從緩存池中拿出來用。典型的應用就是數據連接池,數據連接池中緩存了大量的數據連接,每次程序訪問數據庫時候都可以直接取出這些數據庫連接。實現緩存通常有兩種方式:

1)使用HashMap進行緩存。

2)直接使用某些開源的緩存項目。這些緩存項目的大體原理就是:主動分配一個一定大小的緩存容器,再按照一定的淘汰算法淘汰掉容器中很久不用的對象。後續博文會介紹spring的緩存管理。

7、考慮使用SoftReference

SoftReference是個很好的選擇,當內存足夠時,它的功能相當於普通引用;當內存不夠時候,它會犧牲自己,釋放軟引用所引用的對象。

SoftReference<String> sr = new SoftReference<String>("hello");// 此處初始化一個軟連接,其實接收的是String對象
System.out.println(sr.get());// 得到string對象只需要用到SoftReference的get方法即可


未完待續......







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章