基本概念
內存泄露:程序中動態分配內存給臨時對象,但是對象不會被GC所回收,它始終佔用內存。從而引發內存溢出
內存溢出:程序運行過程中無法申請到足夠的內存而導致的一種錯誤。
內存泄露是導致內存溢出的一種誘因,但不是唯一的因素。
Java堆溢出(OutOfMemoryError:Java heap space)
堆是用來存儲對象實例的,因此如果我們不斷地創建對象,並且使創建的對象不被垃圾回收,那麼當創建的對象過多時,會導致heap內存不足,進而引發OutOfMemoryError異常。
public static void main(String arg[]){
List<Integer> list = new ArrayList<>();
int i=0;
while(true){
list.add(i++);
}
}
上面是一個引發OutOfMemoryError異常的代碼。
通過java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError設置堆內存爲10M,
參數-XX:+HeapDumpOnOutOfMemoryError 異常時打印當前的內存快照以便於後續分析。
Java棧異常(StackOverflowError)
JVM運行時數據區中有一個虛擬機棧的內存區域,此區域的作用是:每個方法在執行時都會創建一個棧幀,用於存儲局部變量,操作數棧,方法出口等信息。一秀線程棧溢出是由於遞歸太深或方法調用層級過多導致的。
public static void main(String arg[]){
test(1);
}
public static void test(int i){
i++;
test(i);
}
以上的代碼創建了一個無限遞歸的調用,當遞歸深度過大時,就會耗盡棧空間,進而導致StackOverflowError異常。
方法區內存溢出(OutOfMemoryError:PermGen space)
在JVM中,方法區主要存放的是類信息、常量、靜態變量等。
如果程序加載的類過多,或者使用反射、GCLIB等這種動態代理生成類的技術,就可能導致方法區發生內存溢出。
避免內存泄露:
1、儘早釋放無用的對象引用
2、字符串處理避免使用String,改用StringBuffer,每一個String對象都佔用一塊獨立的內存
3、儘量少用靜態變量,因爲靜態變量存放在永久代(方法區),永久代基本不參與垃圾回收
4、避免在循環中創建對象