java.lang.OutOfMemoryError: Java heap space
Dumping heap to
java_pid10604.hprof ...
Heap dump file created [29234562 bytes in 0.214 secs]
Heap
PSYoungGen total 9216K, used 8154K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 99% used [0x00000000ff600000,0x00000000ffdf6a10,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
ParOldGen total 10240K, used 9292K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 90% used [0x00000000fec00000,0x00000000ff513390,0x00000000ff600000)
Metaspace used 4979K, capacity 5182K, committed 5248K, reserved 1056768K
class space used 591K, capacity 626K, committed 640K, reserved 1048576K
异常分析:
这个异常咱们要借助Memory Analyzer工具来查看内存溢出的是哪一个对象,刷新整个项目,点击根目录下的java_pid10604.hprof,默认是Overview视图,上面是一个显眼的饼图:
在这个饼图里面,咱们能够看到有一个可疑对象在总共16.4MB的内存里,它占用了15.5MB的内存,占用了94.5%的内存。
在饼图的左下方,这个报告告诉咱们这个内存溢出发生在main这个线程里面。
接下来咱们固然想知道究竟是哪一个对象干的,那么找到饼图的下方还有一些工具:
点击Histogram连接,打开Histogram视图:
咱们发如今Objets这一栏,最多的一个对象实例居然达到810327个,这个对象类是com.virtual.VirtualTest。那么很清楚了,咱们new出了太多这个类对象,致使垃圾内存溢出。
在dominator_tree视图中,能够看到main线程占用了94.02%的内存
在上图中,咱们能够看到该.hprof文件存放的路径、大小、生成时间、格式、报告中总共产生多少对象,堆大小(16.4MB)等信息。
例子2
/*** 以Run AS -> Run Configurations运行。
* 并设置 VM arguments参数以下:
* -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
* 注意:-XX:+HeapDumpOnOutOfMemoryError参数将会使项目根目录下产生java_*.hprof文件*/@Testpublic voidtestOutOfMemory2(){
List list = new ArrayList();for(int i=0;i<10000000;i++){
String str= newString();
list.add(str);
}
}
执行代码后,控制台抛出异常以下:
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to
java_pid3360.hprof ...
Heap dump file created [12525143 bytes in 0.136 secs]
异常分析:
Sun 官方对此的定义是:“并行/并发回收器在GC回收时间过长时会抛出OutOfMemroyError。过长的定义是,超过98%的时间用来作GC而且回收了不到2%的堆内存。用来避免内存太小形成应用不能正常工做。“
意思就是GC用尽了全力可仍是来不及回收你new出来的那么多string对象,并且list对象愈来愈大,你还往里面塞对象,还让它活着,你还不让我回收,因而……呵呵……我挂了(>﹏<)
可是我抛出这个异常的目的就是在JVM完全死了以前告诉你我挂了,好让你来得及实施一些紧急措施,好比紧急保存之类。
参考文章《java.lang.OutOfMemoryError:GC overhead limit exceeded填坑心得》
http://www.cnblogs.com/hucn/p/3572384.html
总结
到目前为止,我还没能从Eclipse Memory Analyzer工具中发现可以区分出java内存泄漏(Memory Leak)和内存溢出(Memory Overflow)这两种状态的直接证据。
我的理解为:
java内存泄漏(Memory Leak) 当new出不少对象,而GC没法及时回收这些对象时,会致使内存泄漏。
内存溢出(Memory Overflow) 当一个对象长时间存活,且占用内存巨大直接威胁到总内存时,会致使内存溢出。
如下是其它已在JDK1.8版本中再也不报内存溢出的代码:
举例1
/*** 在JDK1.8中不会抛出异常!!!!
* 以Run AS -> Run Configurations运行。 并设置 VM arguments参数以下:
* -Xss128k -XX:+HeapDumpOnOutOfMemoryError
* 注意:-XX:+HeapDumpOnOutOfMemoryError参数将会使项目根目录下产生java_*.hprof文件*/@Testpublic voidtestOutOfMemory_noError() {int stackLength = 1;try{while (true) {
stackLength= stackLength + 1;
System.out.println("stack length ==" +stackLength);
}
}catch(Throwable t) {
System.out.println("stack length : " +stackLength);throwt;
}
}
举例2
/*** 在JDK1.8中不会抛出异常!!!! 可是会使操做系统假死。
* 以Run AS -> Run Configurations运行。 并设置 VM arguments参数以下:
* -Xss2M -XX:+HeapDumpOnOutOfMemoryError
* 注意:-XX:+HeapDumpOnOutOfMemoryError参数将会使项目根目录下产生java_*.hprof文件*/@Testpublic voidtestOutOfMemory_noError2() {while (true) {
Thread t= new Thread(newRunnable() {
@Overridepublic voidrun() {while (true) {
}
}
});
t.start();
}
}
举例3
/*** 在JDK1.8中不会抛出异常!!!!
* 以Run AS -> Run Configurations运行。 并设置 VM arguments参数以下:
* -XX:PermSize=10M -XX:MaxPermSize=10M -XX:+HeapDumpOnOutOfMemoryError
* 注意:-XX:+HeapDumpOnOutOfMemoryError参数将会使项目根目录下产生java_*.hprof文件*/@Testpublic voidtestOutOfMemory_noError3() {
List list = new ArrayList();int i=0;while (true) {
list.add(String.valueOf(i));
}
}
举例4
/*** 在JDK1.8中不会抛出异常!!!!
* 以Run AS -> Run Configurations运行。 并设置 VM arguments参数以下: -Xms10m -Xmx10m
* -XX:PermSize=10M -XX:MaxPermSize=10M -XX:+HeapDumpOnOutOfMemoryError
* 注意:-XX:+HeapDumpOnOutOfMemoryError参数将会使项目根目录下产生java_*.hprof文件*/@Testpublic voidtestOutOfMemory_noError4() {while(true){
Enhancer enhancer= newEnhancer();
enhancer.setSuperclass(this.getClass());
enhancer.setUseCache(false);
enhancer.setCallback(newMethodInterceptor() {
@OverridepublicObject intercept(Object obj, Method method, Object[] args,
MethodProxy proxy)throwsThrowable {returnproxy.invoke(obj, args);
}
});
enhancer.create();
}
}