嘗試解答java內存問題

  在園子中看見了這個園友的問題,高手指點一下,關於編寫Java程序讓Jvm崩潰,恰巧這兩天看了點相關的東西,也嘗試了一下,下面是仁兄提出的第一個疑問,我來複現一下:  

package jvm;
public class Crash {
    public static void main(String[] args) {
        // Object[] o = {“abc”};初始值賦值,不會有影響。
        Object[] o = null;
        while (true) {
            o = new Object[] { o };
            // 輸出的話,jvm就不會崩潰。
            // System.out.println(o);
        }
    }
}

  如果我直接運行這個程序,等了好久也沒有出現下面的異常,因爲什麼和那個兄臺的結果不一樣,答案很簡單就是我們的環境不一樣,jvm的運行參數也不一樣:  

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space      at jvm.Crash.main(Crash.java:10)

  下面看一下在我執行這段代碼什麼都不加的情況下的jps的監控信息:  

C:\Users\Think>jps -v  7888 org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar -Dosgi.requiredJavaVe  rsion=1.6 -Xms40m -Xmx512m -XX:MaxPermSize=256m  7772 Jps -Dapplication.home=E:\Program Files\Java\jdk1.7.0_40 -Xms8m  7108 Crash -Dfile.encoding=UTF-8 

  其中這條記錄7108 Crash -Dfile.encoding=UTF-8就是我們執行的程序,在下面也看到了有4個垃圾回收的線程在進行內存回收,並沒有指定heap和stack的大小,使用的都是默認值,我覺得我可以用這個程序出拋出stack和heap的異常,下面我把虛擬機運行的堆的參數改小了,改成5M吧:具體方法查看我的這篇從內存溢出看Java 環境中的內存結構

151803412134528.jpg

  執行,出現瞭如下問題,  

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded      at jvm.Crash.main(Crash.java:10)

  可以在sun的網站上找到這個Bug的原因以及解決辦法:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html,大概意思就是我花了太多的時間(98%),但是回收的垃圾太少了(2%)。

he concurrent collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.

  加上-XX:-UseGCOverheadLimit參數以後通過jps命令查看參數:

151811563531559.jpg

  出現:  

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space      at jvm.Crash.main(Crash.java:10)

  加上輸出語句以後代碼如下:  

public class Crash {
    public static void main(String[] args) {
        // Object[] o = {“abc”};初始值賦值,不會有影響。
        Object[] o = null;
        while (true) {
            o = new Object[] { o };
            // 輸出的話,jvm就不會崩潰。
            System.out.println(o);
        }
    }
}

  再次執行程序,參數沒有變化,結果依然出現異常:  

[Ljava.lang.Object;@72e0726b
[Ljava.lang.Object;@63c6472d
[Ljava.lang.Object;@5c71c17e
[Ljava.lang.Object;@786aa48e
[Ljava.lang.Object;@437f3fe
[Ljava.lang.Object;@725d61a4
[Ljava.lang.Object;@402b2861
[Ljava.lang.Object;@94dc811
[Ljava.lang.Object;@7e6d0650
[Ljava.lang.Object;@4d5f4924
[Ljava.lang.Object;@20c88c8a
[Ljava.lang.Object;@57d74d5f
[Ljava.lang.Object;@3f8d2560
[Ljava.lang.Object;@1b663c05
[Ljava.lang.Object;@2046942e
[Ljava.lang.Object;@184bcffd
[Ljava.lang.Object;@1b97d23c
[Ljava.lang.Object;@6207775d
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Unknown Source)
    at java.lang.String.<init>(Unknown Source)
    at java.lang.Integer.toUnsignedString(Unknown Source)
    at java.lang.Integer.toHexString(Unknown Source)
    at java.lang.Object.toString(Object.java:237)
    at java.lang.String.valueOf(Unknown Source)
    at java.io.PrintStream.println(Unknown Source)
    at jvm.Crash.main(Crash.java:12)

  輸出的時候將上面的日誌內容省略了一部分。接下來是第二個例子,要知道在堆中保存的是對象的實例,在例子中:  

JvmBean j = null;        while (true) {          j = new JvmBean(j);              // 無論輸出不輸出,jvm都會崩潰              // System.out.println(j);  }

   很顯然和第一個Object的例子不一樣,看着JbmBean的定義:  

package jvm;
public class JvmBean {
    JvmBean bean = new JvmBean(this);
            
    public JvmBean(JvmBean bean){
        this.bean = bean;
    }
}

  就知道這個程序跟門就沒有循環,在第一次進到循環的時候就掛了。// System.out.println(j);這句根本就執行不到。OK,我幫你修改一下:把Jvm類改爲如下:  

public class JvmBean {
    JvmBean bean = null;
    public JvmBean(JvmBean bean) {
        System.out.println(1);
        this.bean = bean;
    }
}

  然後改一下JVM的運行參數:

151935581822454.jpg

  運行結果如下:  

public class JvmBean {
    JvmBean bean = null;
    public JvmBean(JvmBean bean) {
        System.out.println(1);
        this.bean = bean;
    }
}

  所以我猜測你在第二個例子自己寫的類中拋出的異常應該不是你想象中的場景。



  收拾收拾回家,希望能解答你的疑惑。








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