1.3 OutOfMemoryError异常
在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError异常的可能。
1.3.1 Java堆溢出
Java堆的OOM异常是实际应用中常见的内存溢出异常情况,解决一般先通过内存印象分析工具对Dump出来的堆转存快照进行分析。重点是确认内存中的对象十分是必要的,也就是分清是出现了内存泄漏还是内存溢出
-
内存泄漏----进一步通过工具查看泄漏对象到GC Roots的引用链,找到泄漏代码位置
-
内存溢出---检查虚拟机的堆参数与机器的物理内存是否还可以调大,从代码上检查是否存在某些对象的生命周期过长。持有状态过长的情况
1.3.2 虚拟机栈和本地方法栈溢出
-
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
-
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
单个线程下,无论是由于栈帧太大还是虚拟机栈容量太小了,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常。
操作系统分配给每个进程的内存是有限制的。
1.3.3 方法区和运行时常量池溢出
在JDK1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回永久代中这个字符串实例的引用,而由StringBuilder创建的字符串实例在Java堆上。
JDK1.7后,intern()方法不会再复制实例,只是在常量池中记录首次出现的实例引用。
在动态生成大量Class的应用中,需要特别注意类的回收状况。
1.3.4 本机直接内存溢出
使用DirectByteBuffer分配内存也会抛出异常,但它抛出异常时没有真正向操作系统申请分配内存,而是通过计算得知内存无法分配,于是手动抛出异常,真正申请分配内存的方法是unsafe.allocateMemory()。
由DirectMemory导致的内存溢出,一个明显的特征是在Heap Dump文件中不会看见明显的异常。