线上排查Class、Jar加载问题的一般方法

问题背景

本问题源于《ojdbc6中OraclePreparedStatement的ArrayIndexOutOfBoundsException异常BUG-6396242》这篇博文中最后思考的问题。
假如你的线上环境没有安装arthas,也无法追加–verbose:class或-XX:+TraceClassLoading然后重启,那么如何来定位具体class来自哪个jar包呢?

解决方法

使用中间件产品模块

  • WebSphere

    Class Loader Viewer:Admin console -> Troubleshooting -> Class Loader Viewer

  • WebLogic

    Classloader Analysis Tool (CAT):

    10.3.x 版本以后的版本Development模式中Deployments -> app_name -> Testing -> Classloader ->Analysis Tool.

    但对于Production模式而言,则需要手动部署wls-cat.war,这种方式在线上环境意义不大。

使用Linux的lsof命令

lsof(List of Open Files)本质上是读取内存文件系统/proc/pid下的各种文件操作符,在一切皆文件的Linux世界没有lsof看不到的存在。

lsof –p <pid>

使用dump文件追踪相关的jar信息

使用jmap或者arthas拿到进程dump信息(线上环境要注意dump过程对机器的影响),然后jhat或者mat进行分析,这里为了方便使用mat。
首先查询出已知类的Classloader的所有实例,然后通过其成员寻找相关的加载路径和加载地址。

Tomcat


Tomcat几乎全部的jar都是由WebappClassLoader负责加载。

Weblogic


weblogic的AppClassLoader只加载了自定义domain里面的的相关jar,最终并没有涉及我们应用自身的/WEB-INF/lib下的jar

思考总结

  • 应用运维角度
    对于成熟的中间件产品来说应该使用专门的依赖库分析工具。

  • 系统运维角度
    利用lsof命令或者获取/proc/pid信息可以获取每个进程持有的相关资源当然包括打开的文件。

  • 开发人员角度
    通过jvm相关工具(jmap+jhat)可以拿到内存中任意class类的Classloader的实例以及其成员,当然这需要开发人员的配合或者运维人员具有一定的开发经验。

综合来看,三个角度中从开发角度考虑是最繁琐的。开发人员可以在开发测试阶段完全从代码层面跟踪具体问题,当然前提是测试发现了问题。

参考链接:
https://docs.oracle.com/cd/E24329_01/web.1211/e24368/classloading.htm#WLPRG495

原文地址:https://www.cnblogs.com/elfcafe/p/12987036.html