对jvm常见内存相关的Error来分析原因
java.lang.OutOfMemoryError: Java heap space
堆内存溢出
出现原因
- 代码中可能存在大对象分配
- 可能存在内存泄露,导致在多次GC之后,还是无法找到一块足够大的内存容纳当前对象
- 堆内存设置过小,不够用了
解决方法
- 检查是否存在大对象的分配,最有可能的是大数组分配
- 通过jmap命令,把堆内存dump下来,使用mat工具分析一下,检查是否存在内存泄露的问题
- 如果没有找到明显的内存泄露,使用 -Xmx 加大堆内存
- 还有一点容易被忽略,检查是否有大量的自定义的 Finalizable 对象,也有可能是框架内部提供的,考虑其存在的必要性
java.lang.OutOfMemoryError: PermGen space
java.lang.OutOfMemoryError: Metaspace
永久代/元空间溢出
JDK1.8之前-XX:MaxPermSize ,之后-XX:MetaspaceSize 永久代是 HotSot 虚拟机对方法区的具体实现,存放了被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等。
出现原因
- 有大量的Class或者JSP页面
- jdk8之前(8之后常量池放到堆里)大量字符串常量也会导致溢出
- 运行期间生成了大量的代理类(动态代理),导致方法区被撑爆,无法卸载
- 应用长时间运行,没有重启
解决方法
- 更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改
- 检查代码中是否存在大量的反射操作
- dump之后通过mat检查是否存在大量由于反射生成的代理类
- 放大招,重启JVM
java.lang.StackOverflowError
方法栈溢出1
出现原因
- 由于程序中存在死循环或者深度递归调用造成的
- 栈大小设置太小也会出现此种溢出
解决方法
- 可以通过虚拟机参数-Xss来设置栈的大小
java.lang.OutOfMemoryError : unable to create new native Thread
方法栈溢出2
出现这种异常,基本上都是创建的了大量的线程导致的,以前碰到过一次,通过jstack出来一共8000多个线程。
解决方法
- 通过 -Xss 降低的每个线程栈大小的容量
- 线程总数也受到系统空闲内存和操作系统的限制,检查是否该系统下有此限制:
/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溢出
出现原因
- swap 分区大小分配不足
- 其他进程消耗了所有的内存
解决方法
- 其它服务进程可以选择性的拆分出去
- 加大swap分区大小,或者加大机器内存大小
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
非常规溢出
出现原因
- 这种情况一般是由于不合理的数组分配请求导致的,在为数组分配内存之前,JVM 会执行一项检查。要分配的数组在该平台是否可以寻址(addressable),如果不能寻址(addressable)就会抛出这个错误。 解决方法
解决方法
- 检查你的代码中是否有创建超大数组的地方
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