接https://blog.csdn.net/guzhangyu12345/article/details/84666423 的最后例子,运行时会报如下错误:
[quasar] ERROR: while transforming java/util/IdentityHashMap$KeyIterator: null
java.lang.IllegalArgumentException
at co.paralleluniverse.fibers.instrument.QuasarInstrumentor.getMethodDatabase(QuasarInstrumentor.java:181)
at co.paralleluniverse.fibers.instrument.QuasarInstrumentor.instrumentClass(QuasarInstrumentor.java:108)
at co.paralleluniverse.fibers.instrument.QuasarInstrumentor.instrumentClass(QuasarInstrumentor.java:94)
at co.paralleluniverse.fibers.instrument.JavaAgent$Transformer.transform(JavaAgent.java:209)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.util.IdentityHashMap$KeySet.iterator(IdentityHashMap.java:977)
at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:101)
at java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46)
at java.lang.Shutdown.runHooks(Shutdown.java:123)
at java.lang.Shutdown.sequence(Shutdown.java:167)
at java.lang.Shutdown.shutdown(Shutdown.java:234)
[quasar] ERROR: while transforming java/util/IdentityHashMap$IdentityHashMapIterator: null
java.lang.IllegalArgumentException
at co.paralleluniverse.fibers.instrument.QuasarInstrumentor.getMethodDatabase(QuasarInstrumentor.java:181)
at co.paralleluniverse.fibers.instrument.QuasarInstrumentor.instrumentClass(QuasarInstrumentor.java:108)
at co.paralleluniverse.fibers.instrument.QuasarInstrumentor.instrumentClass(QuasarInstrumentor.java:94)
at co.paralleluniverse.fibers.instrument.JavaAgent$Transformer.transform(JavaAgent.java:209)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.util.IdentityHashMap$KeySet.iterator(IdentityHashMap.java:977)
at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:101)
at java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46)
at java.lang.Shutdown.runHooks(Shutdown.java:123)
at java.lang.Shutdown.sequence(Shutdown.java:167)
at java.lang.Shutdown.shutdown(Shutdown.java:234)
从堆栈分析,从at java.util.IdentityHashMap$KeySet.iterator(IdentityHashMap.java:977) 到transform是一个跳跃,百思不得其解
堆栈最顶端报错的原因是classLoader为空
transform是对字节码的修改,附: ClassLoader javaagent相关的知识:
代理 JAR 文件的清单必须包含
Premain-Class
属性。此属性的值是代理类 的名称。代理类必须实现公共静态premain
方法,该方法的原理与main
应用程序入口点类似。在 Java 虚拟机 (JVM) 初始化后,每个premain
方法将按照指定代理的顺序调用,然后将调用实际的应用程序main
方法。每个premain
方法必须按照依次进行的启动顺序返回。
premain
方法有两种可能的签名。JVM 首先尝试在代理类上调用以下方法:public static void premain(String agentArgs, Instrumentation inst);
如果代理类没有实现此方法,那么 JVM 将尝试调用:
public static void premain(String agentArgs);
如果代理在 VM 启动之后启动,那么代理类还有一个要使用的
agentmain
方法。如果是使用命令行选项启动代理,那么agentmain
方法将不会被调用。代理类将被系统类加载器加载(参见
ClassLoader.getSystemClassLoader
)。系统类加载器是通常加载包含应用程序main
方法的类的类加载器
查看quasar的agent类co.paralleluniverse.fibers.instrument.JavaAgent的相关代码,可以看到其加了一个Transformer,根据jdk的注释:the transformer will be called for every new class definition and every class redefinition. Retransformation capable transformers will also be called on every class retransformation
联想到shutdown时可能触发了new class definition,通过代码分析,触发了java/util/IdentityHashMap$KeyIterator的class define,而该线程Thread[DestroyJavaVM,5,main]不存在对应的ClassLoader,所以会报这个错误。