深入理解JAVA虚拟机之异常诊断
常见的JAVA虚拟机HotSpot虚拟机运行时数据库由5部分构成:方法区,堆,虚拟机栈,本地方法栈,程序计数器。下面列举各个部分可能出现的异常及其出现原因。
1.方法区存放的已被虚拟机加载的类型信息,常量、静态变量、即时编译器编译后的代码缓存等数据。可能出现的异常有OutOfMemoryError,原因可能是创建了过多的常量(不太可能,因为自JDK7起,原本存放在永久代中的字符串常量池被移至Java堆中,故JDK7前的运行池常量溢出报错由OOM:PerGem space变为了OOM:Java heap space),生成大量动态类,大量JSP或动态产生JSP文件的应用(JSP第一次运行时需要编译为Java类)、使用了CGLib字节码增强和动态语言,基于OSGi的应用(即使是同一个类,被不同的加载器加载也会视为不同的类)等。
2.堆是虚拟机所管理的内存中最大的一块,唯一目的是存放对象实例。可能出现的异常有OutOfMemoryError,原因是Java堆中没有内存能够完成实例分配,并且堆也无法再扩展。解决办法:使用参数-Xmx提高最大堆容量。检查是否存在某些对象生命周期过长、持有状态时间过长、存储结构设计不合理等情况。
3.虚拟机栈和本地方法栈发挥的作用非常相似,在HotSpot虚拟机两者合二为一,存储局部变量表、操作数栈、动态连接、方法出口等信息。如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常;出现StackOverflowError的原因可能时本地变量过多或者栈内存容量太小,解决办法:使用-Xss提高栈容量最小值。
如果虚拟机的栈内存允许动态扩展,当扩展栈容量无法申请到足够的内存时,将抛出OutOfMemoryError异常(HotSpot虚拟机不支持扩展,所以只有创建线程申请内存时就因为无法获得足够的内存而出现OutOfMemoryError异常)。出现的原因可能是创建的线程过多,解决办法:减少线程数量,减少最大堆和减少栈容量换取更多的线程(总的内存有限,减去堆和方法区的容量,剩余的内存会多些)。
4.程序计数器不会出现异常。
以上是通过周志明老师的《深入理解Java虚拟机》得到的小结。