Arthas: jdk8下 jad 查看包含lambda的类,导致应用抛出 ClassNotFoundException 和 NoClassDefFoundError 问题

Created on 21 Sep 2020  ·  8Comments  ·  Source: alibaba/arthas

  • [x] 我已经在 issues 里搜索,没有重复的issue。

环境信息

  • arthas-boot.jar 或者 as.sh 的版本: 3.4.1
  • Arthas 版本: 3.4.1
  • 操作系统版本: windows 10 19041.508
  • 目标进程的JVM版本: jdk1.8.0_212
  • 执行arthas-boot的版本: 3.4.1

重现问题的步骤

public class Test {

    public static void main(String[] args) throws InterruptedException {
        Test test = new Test();
        while (true) {
            try {
                AtomicInteger i = new AtomicInteger();
                Runnable runnable = () -> {
                    i.getAndIncrement();
                };
            } catch (NoClassDefFoundError e) {
                e.printStackTrace();
                Thread.sleep(2000);
            }
        }
    }
}

运行上述代码,并用arthas attach,然后使用命令 jad package.Test.
虽然可以正确反编译类的内容,但上述程序开始抛出异常。

java.lang.NoClassDefFoundError: cn/willingxyz/javaagent/Test$$Lambda$1
        at cn.willingxyz.javaagent.Test$$Lambda$1/1156060786.get$Lambda(Unknown Source)
        at cn.willingxyz.javaagent.Test.main(Test.java:18)

可能和 https://bugs.openjdk.java.net/browse/JDK-8145964 这个bug有关,不过jad命令(和其他相关命令)是否能够绕开该bug。

bug

Most helpful comment

同样 watch等命令也会有类似问题,已处理。 watch Test* *

All 8 comments

这两个issue应该是类似问题: https://github.com/alibaba/arthas/issues/747https://github.com/alibaba/arthas/issues/968

这个redefine的bug也可以参考下: https://zhuanlan.zhihu.com/p/91756092

jdk的bug没有太好的办法,只能升到高版本的。

这两个issue应该是类似问题: #747 , #968

这个redefine的bug也可以参考下: https://zhuanlan.zhihu.com/p/91756092

jdk的bug没有太好的办法,只能升到高版本的。

处理lambda类的时候,能够忽略这个lambda类吗,至少不要影响到应用吧

这两个issue应该是类似问题: #747 , #968
这个redefine的bug也可以参考下: https://zhuanlan.zhihu.com/p/91756092
jdk的bug没有太好的办法,只能升到高版本的。

处理lambda类的时候,能够忽略这个lambda类吗,至少不要影响到应用吧

jad命令实际上是触发了一次 retransform ,并没有做其它的修改。 另外,在jdk11上没有这个问题。 还有貌似不是所有有 lambda的都会出现这个问题。 所以也没办法为特定的情况处理。

这两个issue应该是类似问题: #747 , #968
这个redefine的bug也可以参考下: https://zhuanlan.zhihu.com/p/91756092
jdk的bug没有太好的办法,只能升到高版本的。

处理lambda类的时候,能够忽略这个lambda类吗,至少不要影响到应用吧

jad命令实际上是触发了一次 retransform ,并没有做其它的修改。 另外,在jdk11上没有这个问题。 还有貌似不是所有有 lambda的都会出现这个问题。 所以也没办法为特定的情况处理。

我看了源码,反编译某个类的时候,也会retransform它的内部类,这些内部类里就包括了lambda类。
所以,retransform的时候是否能忽略这些lambda类

原始的 Test.class类里,引用的lambda类是 lambda$0

  #66 = Methodref          #1.#67         // Test.lambda$0:(Ljava/util/concurrent/atomic/AtomicInteger;)V
  #67 = NameAndType        #49:#50        // lambda$0:(Ljava/util/concurrent/atomic/AtomicInteger;)V
  #68 = MethodHandle       #6:#66         // invokestatic Test.lambda$0:(Ljava/util/concurrent/atomic/AtomicInteger;)V

调试的栈也是 lambda$0

Thread [Thread-0] (Suspended (breakpoint at line 13 in Test))   
    Test.lambda$0(AtomicInteger) line: 13   
    1620303253.run() line: not available    
    Thread.run() line: 748  


但是抛出异常的栈显示:

java.lang.NoClassDefFoundError: Test$$Lambda$1
    at Test$$Lambda$1/1418481495.get$Lambda(Unknown Source)
    at Test.main(Test.java:12)

可见的确是jdk bug问题。

jdk8 和jdk11的不同之处,应该是 jdk11在 retransform lambda类时,直接抛出了异常。而jdk8还是正常处理,然后导致新的字节码出错。

java.lang.instrument.UnmodifiableClassException: null
        at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
        at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:167)
        at com.taobao.arthas.core.util.InstrumentationUtils.retransformClasses(InstrumentationUtils.java:25)
        at com.taobao.arthas.core.command.klass100.JadCommand.processExactMatch(JadCommand.java:166)
        at com.taobao.arthas.core.command.klass100.JadCommand.process(JadCommand.java:147)
        at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
        at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
        at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
        at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
        at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:834)

实际上 jdk11,会retransform lambda类时,没回调 ClassFileTransformer 就抛出异常了。 也就是说 jdk11下面,拿不到 lambda类的字节码。

但是jdk8下可以拿到,但是会导致应用出错。 应用实际是先抛出 ClassNotFoundException ,然后第二次就会变成 NoClassDefFoundError 。

java.lang.NoClassDefFoundError: Test$$Lambda$1
    at Test$$Lambda$1/1418481495.get$Lambda(Unknown Source)
    at Test.main(Test.java:12)
Caused by: java.lang.ClassNotFoundException: Test$$Lambda$1
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 2 more
java.lang.NoClassDefFoundError: Test$$Lambda$1
    at Test$$Lambda$1/1418481495.get$Lambda(Unknown Source)
    at Test.main(Test.java:12)

目前而言,最好是直接不 retransform lambda类。

同样 watch等命令也会有类似问题,已处理。 watch Test* *

Was this page helpful?
0 / 5 - 0 ratings