在实际的开发中我们可能会遇到各种各样的内存溢出(OutOfMemoryError)问题,我在开发的时候就遇到过这样的情况。当时是报的这样异常
- 1
- 2
- 1
- 2
造成这个原因的是我们的tomcat下方了好几个web程序,而且每个程序都有大量的spring ,hibernate的jar包,并且这几个程序的jar基本上都是一样的。这就造成了重复加载的情况,直接导致我的永久区溢出。后来把公共的jar提出来放在一个share文件夹下,这样就可以了。而且Spring,Hibernate,在对类进行增强时,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的class可以加载如内存。
java堆溢出
java堆用于存储对象,所有不断的创建对象并且在GC Roots到对象之间有可达路径避免垃圾回收清除这些对象,在对象数量达到最大堆的容量限制后就会产生堆溢出
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
虚拟机栈和本地方法栈溢出
栈容量的设置由参数-Xss参数设置。java虚拟机规范中描述的异常
- 如果线程请求的栈深度大于虚拟机所运行的最大深度,将抛出StackOverflowError
- 如果虚拟机在扩展时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
实验表明:在当个线程下,无论由于栈帧太大还是虚拟机栈容量太小,当内存无法分配时,虚拟机抛出的都是StackOverflowErroe异常
方法区和运行时常量池溢出
运行时 常量池是方法区的一部分。我们通过一个String.intern()方法来测试。String.intern()是一个本地方法,如果字符串常量池中已经包含一个等于此String对象,则返回代表池中这个字符串的String对象;否则将此String对象包含的字符串添加到常量池中,并且返回该String对象的引用。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
这里我一开始是用jre7的,结果没反应,改为jre6才有产生这样的情况。
JVM上的动态语言通常会持续创建类来实现语言的动态性,也会经常造成PermGen space异常
直接内存溢出
DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不指定,默认与java堆的最大值-Xmx一样。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
由DirectMemory导致的内存溢出,一个很明显的特征是在Heap Dump文件中不会看见明显的异常。如果发现OOM情况后Dump文件很小,而程序中又使用了NIO,可以检查是不是直接内存溢出。