前言
公司线上的一个war程序,跑着跑着挂掉了。有点慌,因为找不到问题所在,也担心下次又出现这个问题。总不是每次都通过重启来解决吧?于是各种搜索,也因此了解到了一些新的东西,如visualVm。接触到内存溢出、dump文件分析、visualVm这些新东西,内心有点小激动,因此也记录一下。
问题——出现OutOfMemoryError
重启服务后,回头找问题。查看代码日志,发现报的错误是连接数据库出问题。没道理啊,怎么跑着跑着就访问不了数据库了呢。于是查看tomcat下的logs文件里的cataline日志和localhost日志,发现报的错误是:
03-Mar-2019 14:44:12.600 SEVERE [http-nio-8080-Acceptor-0] org.apache.tomcat.util.net.NioEndpoint$Acceptor.run
java.lang.OutOfMemoryError: Java heap space
at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
at java.nio.ByteBuffer.allocate(ByteBuffer.java:335)
at org.apache.tomcat.util.net.NioEndpoint$NioBufferHandler.<init>(NioEndpoint.java:1432)
at org.apache.tomcat.util.net.NioEndpoint.setSocketOptions(NioEndpoint.java:557)
at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:707)
at java.lang.Thread.run(Thread.java:748)
根据网上的资料,造成OutOfMemoryError:Java heap space异常的原因是Java堆上已经没有空闲的空间,JVM无法继续执行程序了。
引起堆内存不足的可能原因大概有这么些:
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
- 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
- 代码中存在死循环或循环产生过多重复的对象实体; 使用的第三方软件中的BUG; 启动参数内存值设定的过小;
- 使用的第三方软件中的BUG;
- 启动参数内存值设定的过小;
- 加载太多资源到内存,导致GC耗时较多加载太多资源到内存,导致GC耗时较多
dump文件
可是单凭日志的错误信息我也没法定位到问题,没法知道到底资源在哪里泄漏了。在网上查了一些资料,得知,可以设置jvm参数,当出现OutOfMemory异常的时候生成一个dump文件,然后再通过dump文件来定位问题。
于是在tomcat中进行了JVM参数的配置,这个也是借助网络的力量,才知道要怎么做的:
在/tomcat/bin/cataline.sh中,增加如下代码:
JAVA_OPTS="-server -Xms3072M -Xmx3072M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/tomcat/heapdump.hprof"
上面的配置表示设置初始堆为3g,最大堆为3g,并且设置了出现OutOfMemory错误时生成dump文件。这里也没写在哪个位置添加这串代码,参考文末的参考链接把。
然后重启tomcat服务。这样下次再出现这个错误的时候就会生成dump文件,就可以通过dump文件去定位问题了。
VisualVM工具
那么假设现在有dump文件了,该怎么去分析,怎么去定位?
在思考以及尝试解决这个问题的过程中,又了解到了visualVM这个工具。
对visualVm的初步认识,是通过这篇文章:
记一次解决OutOfMemoryError: Java heap space详细过程与解决思路(jvisualvm解决问题案例详细分析),作者写的有趣又有质量!!极力推荐!!!
VisualVM 是一款免费的,集成了多个 JDK 命令行工具的可视化工具,它能为您提供强大的分析能力,对 Java 应用程序做性能分析和调优。这些功能包括生成和分析海量数据、跟踪内存泄漏、监控垃圾回收器、执行内存和 CPU 分析。
首先,写一个可以触发OutOfMemory的代码:
public class MyTest1 {
static class OOMObject {
}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while (true) {//死循环
list.add(new OOMObject());//循环往容器中添加对象,并且这些对象无法被释放
}
}
}
然后在idea中配置vm参数:
-Xms20M
-Xmx20M
-Xmn10M
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D:\heapdump.hprof
这里的vm配置,其实就是在服务器上的cataline.sh文件中配置一个道理,都是设置vm参数。
然后调用main方法,很快就会出现OutOfMemory错误了,同时也会得到一个dump文件。然后就可以通过visualVm去解析了。这里不对visualVm的使用进行讲述了,网上也有很多的教程。但我觉得最重要的还是自己去动手操作。通过dump文件,可以解析出最占用资源的是哪个对象,可以看出是不是某个对象特别特别的大,某类型的对象数量是不是高达几万个。
visualVm的功能不仅仅是可以分析dump文件,还可以访问远程服务器的jvm。通过在服务器进行一些与jstatd指令有关的配置并执行它。然后通过visualVm工具进行远程访问,这样,就可以远程查看服务器上jvm的堆内存使用的折线图了,十分的直观,也可以看到远程服务器上的vm参数。如下图所示:
至于visualVm连接远程服务器jvm的操作流程,这里也不列出来了,操作流程也放在文末的链接中。我也是参考别人文章操作的。
最后
可能写的让人看的不知所云,觉得文章没有一个,既没有给出这次出现OutOfMemory的原因,也没有给出VisualVM的具体使用方法。
但其实想说的是,对于这种程序突然挂掉的问题,公司里也没谁可以帮忙解决没谁可以请教,只能自己去思考,自己去找解决。虽然,现在也还没解决掉这个问题,但是至少也有了一些相应的措施,如下次出现这个问题的时候可以分析dump去定位问题。另外,这些东西也是新的东西,之前也没接触到,因此内心也有点小激动,也因此认识了visualVm这个之前没听过的强大的工具,感觉很有意思。
也期待着下次这个问题再出现时自己能够把问题给解决!
参考链接
出现OutOfMemory的各种详细异常:https://blog.csdn.net/chen8238065/article/details/80860444
出现java heap space的根本原因:https://blog.csdn.net/esuom_gib/article/details/79942273
出现OutOfMemory可能的原因:https://blog.csdn.net/HBQandJAVA/article/details/80361900
tomcat如何设置jvm参数:https://www.cnblogs.com/101key/p/6876777.html
jvm各参数的含义参考:http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html
jvm参数以及用法:https://www.cnblogs.com/z-sm/p/6253335.html
大神讲述他处理OutOfMemory的思路与操作:https://blog.csdn.net/lyflyyvip/article/details/82288719
写出OutOfMemory的代码:https://blog.csdn.net/wwd0501/article/details/78655942
visualVm的操作与使用:https://www.cnblogs.com/wangtao1993/p/6144183.html
visualVm的操作与使用:https://www.2cto.com/kf/201801/710669.html