背景:两个问题,
1、tomcat的自带的reload机制(就是直接覆盖webapp的war包),但是多次之后,会产生metaspace溢出。
2、有一次生产环境程序跑着跑着metaspace溢出了。
metaspace存储的类加载信息,metaspace使用本地内存,默认情况下,大小仅受本地内存限制
类被垃圾回收的条件是:
1、这个类没有了引用。
2、这个类没有了实例。
3、这个类的类加载器被回收了。
但是,在我本地不停的用jvisualVm监控tomcat的手发现,卸载应用,不会卸载类,metaspace空间并不会回收。而且,发现一般应用,会引用了各种包,各种相互引用,最后,很难追究到根引用,反正tomcat卸载application不卸载类这个问题,好像很难解决,除非优化jvm。所以内存泄漏这个事情基本无法解决。
在实验中发现的事情:
1、metaspace溢出,tomcat的jvm并不会关闭,依然可以使用jvisualVM或者arthas连上,所以如果生产环境发生这种metaspace溢出,可以使用arthas看一下metaspace的状态,是不是maxMetaspace设置小了。
2、java -XX:+PrintFlagsInitial | grep MetaspaceSize可以查看MetaspaceSize默认大小,但是其实用处不大,默认基本都很大。
3、可以通过 jinfo -flags 32238查看程序的启动参数(如果多个jdk,需要找到具体得jdk得jinfo工具)。arthas的jvm命令也可以看到启动参数,jvsisulaVm也可以看到启动参数。
4、如果tomcat没有限制比如set JAVA_OPTS=%JAVA_OPTS% -XX:MaxMetaspaceSize=100m限制内存大小的话,很难out。而linux则metaspace不会有限制。
5、如果没有指定maxMetaspace的大小,又存在内存metaspace泄漏的话,比如不停的替换war包热部署,那么很可能导致metaspace占用大量的内存。
6、jvisual的maxMetaspace的监控好像不太准确,也可能是我没看明白。
7、arthas的使用。虽然jvisualVm共呢个也很强大,jvisualVm相对于arthas不好的地方就是,jvisualVm远程监控需要开通端口,但是生产环境,开通端口是比较麻烦的事情,所以arthas这种可以直接在linux上运行的会比较友好。arthas可以看到jvm状态,包括jvm的各个内存区域的状态,各个线程cpu的状态、方法的调用时长等等,功能很强大。
基本使用:
1) wget https://alibaba.github.io/arthas/arthas-boot.jar
2)jps -lv 查看到pid
3)java -jar arthas-boot.jar
如果出现这种错误,说明上次没有执行shutdown关闭,则提示执行:java -jar ~/.arthas/lib/3.1.7/arthas/arthas-client.jar 127.0.0.1 3658 -c "stop" 关闭上次session,再启动arthas-boot.jar
4)dashboard命令
结论:如果内存不care,开发环境可以限制一个比较大的maxmetaspace,然后不停的替换war包热部署tomcat,毕竟这样比重启服务器快,但是生产环境我觉得没有必要设置maxmetaspace,因为如果设置的比较大还好,如果设置的比较小,生产环境产生out of memory metaspace就不太好了,metaspace的初衷就是不要产生out of memory metaspace,还有就是生产环境不要使用替换war包热部署程序,因为会造成metaspace内存溢出,造成内存的浪费。