对jvm常见内存相关的Error来分析原因


java.lang.OutOfMemoryError: Java heap space

堆内存溢出

出现原因

  1. 代码中可能存在大对象分配
  2. 可能存在内存泄露,导致在多次GC之后,还是无法找到一块足够大的内存容纳当前对象
  3. 堆内存设置过小,不够用了

解决方法

  1. 检查是否存在大对象的分配,最有可能的是大数组分配
  2. 通过jmap命令,把堆内存dump下来,使用mat工具分析一下,检查是否存在内存泄露的问题
  3. 如果没有找到明显的内存泄露,使用 -Xmx 加大堆内存
  4. 还有一点容易被忽略,检查是否有大量的自定义的 Finalizable 对象,也有可能是框架内部提供的,考虑其存在的必要性



java.lang.OutOfMemoryError: PermGen space

java.lang.OutOfMemoryError: Metaspace

永久代/元空间溢出

JDK1.8之前-XX:MaxPermSize ,之后-XX:MetaspaceSize 永久代是 HotSot 虚拟机对方法区的具体实现,存放了被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等。

出现原因

  1. 有大量的Class或者JSP页面
  2. jdk8之前(8之后常量池放到堆里)大量字符串常量也会导致溢出
  3. 运行期间生成了大量的代理类(动态代理),导致方法区被撑爆,无法卸载
  4. 应用长时间运行,没有重启

解决方法

  1. 更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改
  2. 检查代码中是否存在大量的反射操作
  3. dump之后通过mat检查是否存在大量由于反射生成的代理类
  4. 放大招,重启JVM



java.lang.StackOverflowError

方法栈溢出1

出现原因

  1. 由于程序中存在死循环或者深度递归调用造成的
  2. 栈大小设置太小也会出现此种溢出

解决方法

  1. 可以通过虚拟机参数-Xss来设置栈的大小



java.lang.OutOfMemoryError : unable to create new native Thread

方法栈溢出2

出现这种异常,基本上都是创建的了大量的线程导致的,以前碰到过一次,通过jstack出来一共8000多个线程。

解决方法

  1. 通过 -Xss 降低的每个线程栈大小的容量
  2. 线程总数也受到系统空闲内存和操作系统的限制,检查是否该系统下有此限制: /proc/sys/kernel/pid_max
    /proc/sys/kernel/thread-max
    maxuserprocess(ulimit -u)
    /proc/sys/vm/maxmapcount



java.lang.OutOfMemoryError: Out of swap space

Swap溢出

出现原因

  1. swap 分区大小分配不足
  2. 其他进程消耗了所有的内存

解决方法

  1. 其它服务进程可以选择性的拆分出去
  2. 加大swap分区大小,或者加大机器内存大小



java.lang.OutOfMemoryError: Requested array size exceeds VM limit

非常规溢出

出现原因

  1. 这种情况一般是由于不合理的数组分配请求导致的,在为数组分配内存之前,JVM 会执行一项检查。要分配的数组在该平台是否可以寻址(addressable),如果不能寻址(addressable)就会抛出这个错误。 解决方法

解决方法

  1. 检查你的代码中是否有创建超大数组的地方

jvm dump 命令

Dump堆内存信息
溢出时自动导出
设置JVM参数
java -Xms10M -Xmx10M -Xmn2M -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=D:\study\log_hprof\gc.hprof -XX:+PrintGCDetails -Xloggc:D:\study\log_gc\gc.log gc.GcTest
设定当发生。不过该方法需要JDK5以上版本。
运行时导出
使用JDK自带的jmap命令。"jmap -dump:format=b,file=heap.bin <pid>"   其中pid可以通过jps获取。
查看使用jvisualvm 或者jhat -port 9090 head.bin