關於編寫Java程序讓Jvm崩潰

今天在書上看到一個做者提出一個問題「怎樣經過編寫Java代碼讓Jvm崩潰」,我看了以後也不懂。帶着問題查了一下,百度知道里面有這樣一個答案:java

 1 package jvm;
 2 
 3 public class Crash {
 4     public static void main(String[] args) {
 5         
 6         //Object[] o = {「abc」};初始值賦值,不會有影響。
 7         Object[] o = null;
 8 
 9         while (true) {
10             o = new Object[] { o };
11             //輸出的話,jvm就不會崩潰。
12             //System.out.println(o);
13         }        
14     }
15 }

程序運行十幾秒以後,控制檯會出現這樣的錯誤:數組

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

很明顯,超出內存空間錯誤。jvm

我將原程序隨意改了一下,如賦初始值等,對程序無影響。函數

但是我將死循環中的o輸出在控制檯的時候,jvm竟然一直都不崩,爲何輸出的話,就不會超出內存空間呢?測試

 

我看來,原程序可以使Jvm崩潰,是由於死循環中,經過舊對象,不斷建立出新的對象,即創造的對象是互相引用的,因此GC是不會回收它們的,形成堆棧溢出。this

仿照這個例子,我寫了一個簡單的類,模仿例子程序中的數組,以下:spa

 1 package jvm;
 2 
 3 public class JvmBean {
 4 
 5     JvmBean bean = new JvmBean(this);
 6     
 7     public JvmBean(JvmBean bean){
 8         this.bean = bean;
 9     }
10 }

而後簡單測試,以下:code

 1 package jvm;
 2 
 3 public class MyCrash {
 4 
 5     public static void main(String[] args) {
 6         JvmBean j = null;
 7         while(true){
 8             j = new JvmBean(j);
 9             //不管輸出不輸出,jvm都會崩潰
10             //System.out.println(j);
11         }
12     }
13 }

結果即是控制檯輸出以下的錯誤:對象

Exception in thread "main" java.lang.StackOverflowError
    at jvm.JvmBean.<init>(JvmBean.java:5)
    at jvm.JvmBean.<init>(JvmBean.java:5)
    at jvm.JvmBean.<init>(JvmBean.java:5)
    at jvm.JvmBean.<init>(JvmBean.java:5)
    at jvm.JvmBean.<init>(JvmBean.java:5)

一長串的"at jvm.JvmBean.<init>(JvmBean.java:5)",後面的被我省略了。blog

結果看來,一樣也形成了jvm崩潰,但是錯誤類型跟例子程序的不一樣,說堆棧溢出錯誤,而且不管是否輸出,錯誤都同樣發生,爲何呢?

 

 

因爲評論的兩位老兄的熱心指點,兩個問題都水落石出了!

這裏過一下整個流程。

第一個異常 結合天添老兄說的,Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at jvm.Crash.main(Crash.java:10)是由於程序沒法申請到足夠的內存的時候拋出的異常,Object數組o不斷指向新的Object數組,數組元素是原來的Object數組,這使得Object維數愈來愈高。不斷申請內存空間,最終致使超出jvm中堆的最大值。堆內存溢出。爲何輸出打印,時間會延長呢?yahokuma老兄一言驚醒夢中人!輸出打印的話,虛擬機並非不會崩潰,而是崩潰的時間大大延長了。而崩潰時間延長實際上是假象,是由於輸出屬於IO事件,每次輸出CPU都被中斷,IO很耗時,因此,感受上纔會時間延長。

第二個異常,yahokuma 老兄在下面評論中已經說的很清楚了,我這裏搬過來——「類內部的靜態屬性 > 靜態塊 > 對象屬性 > 構造方法。注意這一點,那就是說 bean屬性會先於JvmBean的構造函數被初始化。在你main函數中,new一個 JvmBean的構造函數以前,類內部的JvmBean對象要優先被初始化,這個類內部的屬性bean的內部一樣也包含了一個JvmBean對象須要被初始化,成循環調用,造 成了棧溢出。」因此異常纔會是這個——Exception in thread "main" java.lang.StackOverflowError

我把原JvmBean改一下

 1 package jvm;
 2 
 3 public class JvmBean {
 4 
 5     JvmBean bean = null;
 6     
 7     public JvmBean(JvmBean bean){
 8         this.bean = bean;
 9     }
10 }

這樣最終獲得的結果跟第一個例子同樣了。

 

如何使Jvm崩潰呢?若是想使它堆內存空間不足,形成典型的內存泄漏,能夠建立對象,使它們不斷向深層次引用。產生Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 這樣的錯誤。若是想使他們棧空間不足,最簡單的,就是在方法裏,如構造方法裏不斷申請新的內存空間就夠了,如我第二個錯誤例子的示範。

相關文章
相關標籤/搜索