V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hengyunabc
V2EX  ›  程序员

Arthas 3.5.1 发布:神级特性!内存搜索对象

  •  1
     
  •   hengyunabc ·
    hengyunabc · 254 天前 · 2494 次点击
    这是一个创建于 254 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Arthas是 Alibaba 开源的 Java 诊断工具,深受开发者喜爱。

    以前使用watch等命令时,我们通常要先知道哪个类,调用了哪个函数,然后触发调用。这样有局限:

    1. 线上触发调用比较难
    2. 要 watch 到正确的函数可能要选择多次
    3. 条件表达式 /结果表达式 可能需要多次测试

    另外,如果想要查找内存里的对象,需要 heapdump 再分析。

    Arthas 在最新发布的 3.5.1 版本里,带来神级特性:通过vmtool命令,可以在 JVM 内存搜索对象。

    vmtool 在线教程

    下面以vmtool在线教程为例,演示vmtool命令的功能:

    首先启动任意 spring boot 应用,比如:

    wget https://github.com/hengyunabc/spring-boot-inside/raw/master/demo-arthas-spring-boot/demo-arthas-spring-boot.jar
    java -jar demo-arthas-spring-boot.jar
    

    然后用arthas attach 目标进程,成功之后就可以使用vmtool命令了:

    wget https://arthas.aliyun.com/arthas-boot.jar
    java -jar arthas-boot.jar
    

    查找 jvm 里的字符串对象

    首先,vmtool命令通过getInstances这个 action,在 JVM 里搜索字符串:

    $ vmtool --action getInstances --className java.lang.String
    @String[][
        @String[Sorry, deque too big],
        @String[head=%d tail=%d capacity=%d%n],
        @String[elements=%s%n],
        @String[sun/nio/ch/IOVecWrapper],
        @String[40252e37-8a73-4960-807e-3495addd5b08:1620922383791],
        @String[40252e37-8a73-4960-807e-3495addd5b08:1620922383791],
        @String[sun/nio/ch/AllocatedNativeObject],
        @String[sun/nio/ch/NativeObject],
        @String[sun/nio/ch/IOVecWrapper$Deallocator],
        @String[Java_sun_nio_ch_FileDispatcherImpl_writev0],
    ]
    

    limit 参数

    通过 --limit参数,可以限制返回值数量,避免获取超大数据时对 JVM 造成压力。默认值是 10 。

    所以上面的命令实际上等值于:

    vmtool --action getInstances --className java.lang.String --limit 10
    

    如果设置--limit为负数,则遍历所有对象。

    查找 spring context

    以前的在线教程里,我们需要通过tt命令来拦载 spring 调用,然后获取到 spring context 。

    通过vmtool命令,我们可以直接获取到 srping context:

    $ vmtool --action getInstances \
    --className org.springframework.context.ApplicationContext
    @ApplicationContext[][
        @AnnotationConfigEmbeddedWebApplicationContext[org.springframework.boot[email protected]12028586: startup date [Thu May 13 16:08:38 UTC 2021]; root of context hierarchy],
    ]
    

    指定返回结果展开层数

    getInstances action 返回结果绑定到instances变量上,它是数组。

    通过 -x/--expand 参数可以指定结果的展开层次,默认值是 1 。

    vmtool --action getInstances --className org.springframework.context.ApplicationContext -x 2

    获取 srping bean,执行表达式

    getInstances action 返回结果绑定到instances变量上,它是数组。可以通过--express参数执行指定的表达式。

    比如,查找所有的 spring beans 名字:

    vmtool --action getInstances \
    --className org.springframework.context.ApplicationContext \
    --express 'instances[0].getBeanDefinitionNames()'
    

    比如,调用userController.findUserById(1)函数:

    $ vmtool --action getInstances \
    --className org.springframework.context.ApplicationContext \
    --express 'instances[0].getBean("userController").findUserById(1)'
    @User[
        [email protected][1],
        [email protected][name1],
    ]
    

    查找所有的 spring mapping 对象

    vmtool --action getInstances --className org.springframework.web.servlet.HandlerMapping

    $ vmtool --action getInstances --className org.springframework.web.servlet.HandlerMapping
    @HandlerMapping[][
        @SimpleUrlHandlerMapping[[email protected]5d3819c8],
        @EmptyHandlerMapping[org.springframework.web.servlet.c[email protected]11d509ba],
        @RequestMappingHandlerMapping[org.springframework[email protected]56a5f2e3],
        @WelcomePageHandlerMapping[org.springframework.boot.auto[email protected]4c0a4ed3],
        @EmptyHandlerMapping[org.springframework.web.servlet.c[email protected]51e1f8c3],
        @BeanNameUrlHandlerMapping[or[email protected]68c0a39c],
        @SimpleUrlHandlerMapping[[email protected]110b768d],
    ]
    

    查找所有的 javax.servlet.Filter

    在 Arthas 的在线教程里,我们介绍过怎么排查 http 请求 404/401 的问题。使用的是 trace javax.servlet.Filter *命令。

    现在使用vmtool命令,我们可以直接查找出所有的 Filter 对象,加速定位过程。

    $ vmtool --action getInstances --className javax.servlet.Filter
    @Filter[][
        @OrderedCharacterEncodingFilter[org[email protected]49b69493],
        @OrderedHiddenHttpMethodFilter[or[email protected]5477cb9e],
        @AdminFilter[[email protected]],
        @WsFilter[[email protected]],
        @OrderedRequestContextFilter[[email protected]6bed550e],
        @OrderedHttpPutFormContentFilter[org.[email protected]3e538cba],
    ]
    

    指定 classloader name

    在多 classloader 情况下,还可以指定 classloader 来查找对象:

    vmtool --action getInstances \
     --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader \
     --className org.springframework.context.ApplicationContext
    

    指定 classloader hash

    可以通过sc命令查找到加载 class 的 classloader 。

    $ sc -d org.springframework.context.ApplicationContext
     class-info        org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
     code-source       file:/private/tmp/demo-arthas-spring-boot.jar!/BOOT-INF/lib/spring-boot-1.5.13.RELEASE.jar!/
     name              org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
    ...
     class-loader      [email protected]2
                         [email protected]
                           [email protected]
     classLoaderHash   19469ea2
    

    然后用-c/--classloader 参数指定:

    vmtool --action getInstances \
    -c 19469ea2 \
    --className org.springframework.context.ApplicationContext
    

    强制 GC

    当启用 -XX:+DisableExplicitGC的 JVM 参数之后,调用System.Gc()可能并不会触发 GC 行为。

    vmtool里提供了强制 GC 的功能:

    vmtool --action forceGc
    

    如果应用配置了-verbose:gc参数,则可以在应用的标准输出里看到类似的日志:

    [GC (JvmtiEnv ForceGarbageCollection)  25760K->17039K(349696K), 0.0015299 secs]
    [Full GC (JvmtiEnv ForceGarbageCollection)  17039K->16840K(353792K), 0.0154049 secs]
    

    致谢

    • vmtool功能是在社区开发者dragon-zhang(张子成)的最初 PR 上,多次讨论修改完成的,感谢他的工作,同时欢迎大家提出 PR,参与开发😄。

    总结

    上面只展示使用vmtool命令操作 spring context 的例子。实际上可以应用在很多方面,比如:

    • 查找 RPC 的 Provider/Consumer 实例
    • 查找 MQ 的订阅对象信息
    • 查找 Mybatis 的 mapping 对象

    欢迎大家到 Issue 里分享使用经验: https://github.com/alibaba/arthas/issues

    我们正在寻找小伙伴,特别是深圳的同学,欢迎大家加入。

    12 条回复    2021-05-18 14:20:58 +08:00
    hqs0417
        1
    hqs0417  
       254 天前
    66666
    dqzcwxb
        2
    dqzcwxb  
       254 天前
    这个 cooooooooooooooooooool
    jiangwei2222
        3
    jiangwei2222  
       254 天前 via Android
    第一想法,这玩意拿来写外挂行吗?
    lululau
        4
    lululau  
       254 天前
    赞,要是能用 kotlin / clojure / groovy 作为 expression lang 就好了
    young1lin
        5
    young1lin  
       254 天前
    可以,很棒棒。

    我试了下链接里的 demo,棒棒棒!那个招聘的要求有咩有更具体的呢,大致的方向我好专攻一下。
    hengyunabc
        6
    hengyunabc  
    OP
       254 天前
    @lululau 有几个影响。
    1. ClassLoader 可能会有泄露,比如 groovy 就很多版本都有问题
    2. arthas 目前要支持 jdk6
    3. 这些语言体积通常比较大,使 arthas 本身体积增大
    4. 会对 jvm 本身 meta space 造成压力
    hengyunabc
        7
    hengyunabc  
    OP
       254 天前
    @young1lin
    可以在公众号里加我微信,欢迎投递简历 :)
    Ayanokouji
        8
    Ayanokouji  
       254 天前
    还可以查 jvm 级别 cache
    lululau
        9
    lululau  
       254 天前
    @hengyunabc 是否可以做成可选项,比如在测试环境使用时,一般更在乎使用上是否便利,而对系统稳定性的影响在可接受的范围内用户是可以容忍或者说是忽略的
    hAppyTreeFrienDs
        10
    hAppyTreeFrienDs  
       254 天前
    6666
    hengyunabc
        11
    hengyunabc  
    OP
       254 天前
    @lululau 没有太理解。是否使用 arthas,使用哪个命令,对用户来说本身就是自己做的选择。
    v2orz
        12
    v2orz  
       254 天前
    团队用了快两年,感谢
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3778 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 09:36 · PVG 17:36 · LAX 01:36 · JFK 04:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.