最近遇到服务器报如下异常:
1.Exception in thread "Druid-ConnectionPool-Create-1180222211"
Exception: Java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "Druid-ConnectionPool-Create-1180222211"
2.15-Mar-2017 19:56:05.603 SEVERE [http-nio-12035-exec-10] org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun
java.lang.OutOfMemoryError: Metaspace两种错误皆为内存泄露异常,但是引起原因却不同,第一种为线程引起,第二种为Metaspace 空间不足
如何定位该问题呢?
修改java的参数配置该问题便可解决,如-Xms128m -Xmx512m -XX:MetaspaceSize=24M -XX:MaxMetaspaceSize=512m 但如果配置已经足够高,那该如何定位呢?
问题1:Druid-ConnectionPool-Create-1180222211 线程抛出了OutOfMemoryError 异常,Druid-ConnectionPool 通过字面意思得知是数据库建立链接的线程,该线程一般处理从数据库获取数据存到我们的内存中,所以原因为读取数据过多,存放到内存时造成内存泄露.检查工程停止运行的时间,找到该时间的访问流程,查看代码流程得以解决
问题2:Metaspace 不足导致内存溢出.该问题又当如何定位,用同样的方法找到异常发出时间查看访问流程并未发现任何导致该问题的地方,但是Metaspace的空间只要工程不停止是不会很快被回收的,一段时间内会一直增加,所以要找出空间消耗大的原因就必须知道Metaspace 中存放的数据
java中自带jconsole jvisualvm 等监控工具
简单介绍使用:
监视 :可以看出cpu, 堆 ,metaspace ,类装载数,活动线程数,通过下图可以看出metaspace 上升快速,类加载个数也是上升快速,说明有不合理的类加载流程cpu的查看:top 命令
堆查看:堆中包括新生代 老生代 幸存区,java的临时变量等存到该处,如果超出则报OutOfMemoryError 异常, 同命令 jmap -heap pid
metaspace 查看: metaspace 中 存储类的信息、常量池、方法数据、方法代[包括:静态区(存放静态变量) JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中 等], 原来的永久代被该元空间代替,其中主要是类信息,如果一直加载类,则会报 java.lang.OutOfMemoryError: Metaspace 异常,则会出现以下现象.如果要查看metaspace 里具体有哪些类或对象可以通过 [抽样器_heap dump] 来获取详细信息.
如命令 jstat –gccapacity :可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。其他的可以根据这个类推, OC是old内纯的占用量。
jstat -gc 2060 可以查看所有堆栈大小及使用 包括metaspace
抽样器_内存_快照 :可以获取内存中占用空间较大的对象,如下图proxy 的对象特别多,查看相关使用 proxy代理实例的地方以解决
抽样器_heap dump: 时间较长 ,相当于jmap -dump:live,format=b,file=jmap_dump.prof 7126
且生成的prof 文件可以用jvisualvm 使用可视化视图查看
但是如果找到某个特别的类占用空间比较大,可以查看该类的详情,如下图,可以发现 proxy 的实例 特别多,相关的class有ClassA ,相关ClassA 的代理创建存在特别多,可能有死循环或逻辑不对的代码
线程_dump 线程堆栈信息,存放方法的调用等信息,如果方法递归调用过深则会报StackOverflowError 异常.相当于jstack <pid> 工具,
可以查看线程中是否有死锁状态,通过多次打印栈信息,可以得知哪个线程运行时间较长
visual gc :相当于 jmap -heap 7126 查看各个空间占用情况 及 jstat -gc 7126 2s 100的结合使用
可以查看gc的情况,如果新生代及老生代 gc的频率特别快,那应该查看哪个对象占据空间较大,或是java的配置空间是否合理
抽样器_cpu dump:
cpu查看:
top命令
top - 13:36:17 up 10 days, 7:48, 1 user, load average: 3.77, 4.27, 11.86 平均负载超过1,说明已经造成了拥堵
Tasks: 484 total, 1 running, 483 sleeping, 0 stopped, 0 zombie 运行任务数是否合理
%Cpu(s): 44.5 us, 3.3 sy, 0.0 ni, 51.4 id, 0.0 wa, 0.0 hi, 0.7 si, 0.0 st 用户空间占用cpu 比是否偏大
profiler :太慢不要点,基本不用
了解了以上工具的使用,再回到我们遇到的问题 metaspace 内存溢出.找出占用内存较大的进程,查看内存中占用空间较大的对象,根据该对象找出有问题的代码.