一.內存溢出和內存泄露的區別與聯繫
內存溢出 out of memory,指程序要求的內存超出了系統所能分配的範圍,出現out of memory;比如申請一個int類型,但給了它一個int才能存放的數,就會出現內存溢出,或者是創建一個大的對象,而堆內存放不下這個對象,這也是內存溢出。
內存泄露 memory leak,是指程序在申請內存後,無法釋放已申請的內存空間(指分配出去的內存無法被gc回收)。一次內存泄露危害可以忽略,但內存泄露堆積後果很嚴重,無論多少內存,遲早會被佔光。
因此,我們從上面也可以推斷出內存泄露可能會導致內存溢出。內存溢出會拋出異常,內存泄露不會拋出異常,大多數時候程序看起來是正常運行的。
二.內存溢出和內存泄露的案例
public class demo {//內存溢出案例 public static void main(String[] args) { List<Object> list=new ArrayList<>(); while(true){//申請的內存過大 int[] temp=new int[1000]; list.add(temp); } } }
public class demo {//內存泄露案例 public static void main(String[] args) { Vector<Object> v = new Vector<>(1000); for (int i = 1; i<1000; i++) { Object o = new Object(); v.add(o); o = null; } } }
JVM堆內存溢出:
JVM棧內存溢出
三.內存溢出或泄露原因分析
分析堆內存溢出的原因可能如下:
使用了大量的遞歸或無限遞歸(遞歸中用到了大量的新建的對象)
使用了大量循環或死循環(循環中用到了大量的新建的對象)
類中和引用變量過多使用了Static修飾 如public staitc Student s;在類中的屬性中使用 static修飾的最好只用基本類型或字符串。如public static int i = 0; //public static String str;
數組,List,Map中存放的是對象的引用而不是對象,因爲這些引用會讓對應的對象不能被釋放,會大量存儲在內存中。
分析棧內存溢出的原因可能如下:
使用了大量的遞歸或無限遞歸
使用了大量循環或死循環(如循環中不停調用方法)
list,map,數組等長度過大等。
四.出現內存溢出或內存泄露的解決方案
1.修改JVM啓動參數(-Xms,-Xmx),直接增加虛擬機內存。
2.檢查錯誤日誌。
3.使用內存查看工具查看內存使用情況(如jconsole)
4.對代碼進行仔細分析,找出可能發生內存溢出的位置。
詳細排查方案如下:
檢查在數據庫中取的數據量是否超過內存
檢查是否有過大的集合或對象
檢查是死循環或遞歸是否會導致溢出
檢查是否有大量對象的創建是否會出現內存問題
檢查是否有大量的連接對象或監聽器等未關閉
......
五.在開發中應如何避免出現內存泄露
1.儘量少使用枚舉
2.儘量使用靜態內部類而不是內部類
3.儘量使用輕量級的數據結構
4.養成關閉連接和註銷監聽器的習慣
5.謹慎使用static關鍵字
6.謹慎使用單例模式
......