一次完整的JVM堆外内存泄漏故障排查记录( 六 )


而使用1.8时,因为这些代理类都是通过主线程的Classloader加载的,这个Classloader在程序运行的过程中永远也不会被回收,因此通过其加载的这些代理类也永远不会被回收,这就导致metaspace不断扩张,最终耗尽机器的内存了 。
?
这个问题并不局限于fastjson,只要是需要通过程序加载创建类的地方,就有可能出现这种问题 。「尤其是在框架中,往往大量采用类似ASM、javassist等工具进行字节码增强,而根据上面的分析,在jdk1.8之前,因为大多数情况下动态加载的Class都能够在full gc时得到回收,因此不容易出现问题」,也因此很多框架、工具包并没有针对这个问题做一些处理,一旦升级到1.8之后,这些问题就可能会暴露出来 。
总结问题解决了,接下来复盘下整个排查问题的流程,整个流程暴露了我很多问题,最主要的就是「对于JVM不同版本的内存分配还不够熟悉」,导致了对于老生代和元空间判断失误,走了很多弯路,在直接内存中排查了很久,浪费了很多时间 。
其次,排查需要的「一是仔细,二是全面,」,最好将所有可能性先行整理好,不然很容易陷入自己设定好的排查范围内,走进死胡同不出来 。
最后,总结一下这次的问题带来的收获:

  • JDK1.8开始,自带的hostspot虚拟机取消了过去的永久区,而新增了metaspace区,从功能上看,metaspace可以认为和永久区类似,其最主要的功用也是存放类元数据,但实际的机制则有较大的不同 。
  • 对于JVM里面的内存需要在启动时进行限制,包括我们熟悉的堆内存,也要包括直接内存和元生区,这是保证线上服务正常运行最后的兜底 。
  • 使用类库,请多注意代码的写法,尽量不要出现明显的内存泄漏 。
  • 对于使用了ASM等字节码增强工具的类库,在使用他们时请多加小心(尤其是JDK1.8以后) 。
?
文章撰写不易,请大家多多支持我的原创技术公众号:后端技术漫谈
?
参考观察程序运行时类加载的过程
blog.csdn.net/tenderhearted/article/details/39642275
Metaspace整体介绍(永久代被替换原因、元空间特点、元空间内存查看分析方法)
https://www.cnblogs.com/duanxz/p/3520829.html
java内存占用异常问题常见排查流程(含堆外内存异常)
https://my.oschina.net/haitaohu/blog/3024843
JVM源码分析之堆外内存完全解读
http://lovestblog.cn/blog/2015/05/12/direct-buffer/
JVM 类的卸载
https://www.cnblogs.com/caoxb/p/12735525.html
fastjson在jdk1.8上面开启asm
https://github.com/alibaba/fastjson/issues/385
fastjson:PropertyNamingStrategy_cn
https://github.com/alibaba/fastjson/wiki/PropertyNamingStrategy_cn
警惕动态代理导致的Metaspace内存泄漏问题
https://blog.csdn.net/xyghehehehe/article/details/78820135
关注我我是一名后端开发工程师 。主要关注后端开发,数据安全,爬虫,物联网,边缘计算等方向,欢迎交流 。

【一次完整的JVM堆外内存泄漏故障排查记录】


推荐阅读