关于编写Java程序让Jvm崩溃
2014-04-15 17:16
155 查看
今天在书上看到一个作者提出一个问题“怎样通过编写Java代码让Jvm崩溃”,我看了之后也不懂。带着问题查了一下,百度知道里面有这样一个答案:
程序运行十几秒之后,控制台会出现这样的错误:
很明显,超出内存空间错误。
我将原程序随意改了一下,如赋初始值等,对程序无影响。
可是我将死循环中的o输出在控制台的时候,jvm居然一直都不崩,为什么输出的话,就不会超出内存空间呢?
我看来,原程序能够使Jvm崩溃,是因为死循环中,通过旧对象,不断创建出新的对象,即创造的对象是互相引用的,所以GC是不会回收它们的,造成堆栈溢出。
仿照这个例子,我写了一个简单的类,模仿例子程序中的数组,如下:
然后简单测试,如下:
结果便是控制台输出如下的错误:
一长串的"at jvm.JvmBean.<init>(JvmBean.java:5)",后面的被我省略了。
结果看来,同样也造成了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改一下
这样最终得到的结果跟第一个例子一样了。
如何使Jvm崩溃呢?如果想使它堆内存空间不足,造成典型的内存泄漏,可以创建对象,使它们不断向深层次引用。产生Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 这样的错误。如果想使他们栈空间不足,最简单的,就是在方法里,如构造方法里不断申请新的内存空间就够了,如我第二个错误例子的示范。
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); } } }
程序运行十几秒之后,控制台会出现这样的错误:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at jvm.Crash.main(Crash.java:10)
很明显,超出内存空间错误。
我将原程序随意改了一下,如赋初始值等,对程序无影响。
可是我将死循环中的o输出在控制台的时候,jvm居然一直都不崩,为什么输出的话,就不会超出内存空间呢?
我看来,原程序能够使Jvm崩溃,是因为死循环中,通过旧对象,不断创建出新的对象,即创造的对象是互相引用的,所以GC是不会回收它们的,造成堆栈溢出。
仿照这个例子,我写了一个简单的类,模仿例子程序中的数组,如下:
package jvm; public class JvmBean { JvmBean bean = new JvmBean(this); public JvmBean(JvmBean bean){ this.bean = bean; } }
然后简单测试,如下:
package jvm; public class MyCrash { public static void main(String[] args) { JvmBean j = null; while(true){ j = new JvmBean(j); //无论输出不输出,jvm都会崩溃 //System.out.println(j); } } }
结果便是控制台输出如下的错误:
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)",后面的被我省略了。
结果看来,同样也造成了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改一下
package jvm; public class JvmBean { JvmBean bean = null; public JvmBean(JvmBean bean){ this.bean = bean; } }
这样最终得到的结果跟第一个例子一样了。
如何使Jvm崩溃呢?如果想使它堆内存空间不足,造成典型的内存泄漏,可以创建对象,使它们不断向深层次引用。产生Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 这样的错误。如果想使他们栈空间不足,最简单的,就是在方法里,如构造方法里不断申请新的内存空间就够了,如我第二个错误例子的示范。
相关文章推荐
- 关于编写Java程序让Jvm崩溃
- 用JavaScript编写JVM可成功运行Java程序
- 关于将java程序导成.exe,在没有装jvm的机器上运行
- 关于如何编写与调用java的JNI程序
- 写Java程序让Jvm崩溃
- 讲解关于编写跨平台Java程序时的注意事项
- [置顶] jvm之java程序从编写到执行的结构链路
- java 遇到未知异常使程序崩溃,输出jvm的dump崩溃信息到指定文件,然后杀死此进程
- 通过编写Java代码让Jvm崩溃
- 第4章 流程控制----编写Java程序,应用for循环打印菱形
- 编写跨平台Java程序注意事项
- 新手求助,关于添加隐式intent程序崩溃问题
- 读编写高质量代码--改善java程序的151个建议笔记
- 关于java第一个简单程序错误原因
- 编写java程序访问spark环境
- Java程序的运行机制和JVM
- 在Linux系统上编写并运行程序,以Java程序为例
- Java程序的运行机制和JVM
- java--第14周实验--任务1--.编写多线程程序
- Java 写一个方法判断一个字符串是否对称 "asdfgasdfg"、编写一个程序,将下面的一段文本中的各个单词的字母顺序翻转,