內存溢出和內存泄露分析及解決方案

一.內存溢出和內存泄露的區別與聯繫

  內存溢出 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.謹慎使用單例模式

    ......

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