【发布时间】:2021-12-01 11:11:34
【问题描述】:
我们正在使用 Java 代理来增强应用程序中的一些方法。代理依赖于其他jar,为了方便,我们将代理和依赖打包成一个fatjar,然后通过自定义的类加载器加载依赖的jar。程序可以正常启动,但是很慢,完全启动需要几分钟。 (我统计了每个类的加载时间(在 ClassLoader 中的 loadclass()),发现有些类的加载需要几百毫秒)。同样,当我使用spring boot(也是具有相同依赖项的fatjar)时,它会快得多。
JDK的版本是1.8.0_261。
premain方法如下:
public static void premain(String args, Instrumentation instrumentation) throws Exception {
final AgentLanucher agentLauncher = new AgentLanucher(); //----1
agentLauncher.launch(); //----2
// add transformer
instrumentation.addTransformer(new CustomAgentTransformer);
}
而AgentLauncher的代码如下:
import org.springframework.boot.loader.JarLauncher;
public class AgentLanucher extends JarLauncher {
@Override
protected void launch(String[] args) throws Exception{
super.launch(args);
}
}
在执行标有 (1,2) 的代码时,加载一个类需要很长时间(几十或几百毫秒)。计算加载一个类的时间代码如下:
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
final long start = System.currentTimeMillis();
final Class<?> clazz = super.loadClass(name, resolve);
final long end = System.currentTimeMillis();
System.out.println("Load [" + name + "] : " + (end -start));
return clazz;
}
而且我发现当程序用JDK11运行时,它运行得很快。然后我将版本改回JDK8,但将代码从premain移到了一个单独的线程,它也运行得很快。代码如下:
public static void premain(String args, Instrumentation instrumentation) {
CompletableFuture.runAsync(()->{
final AgentLauncher launcher = new AgentLauncher();
launcher.launch();
instrumentation.addTransformer(new CustomAgentTransformer());
});
}
还有一次尝试,我阻塞了主线程,直到子线程完成。它运行缓慢。代码如下:
public static void premain(String args, Instrumentation instrumentation) {
final CompletableFuture<Void> initTask = CompletableFuture.runAsync(() -> {
final AgentLauncher launcher = new AgentLauncher();
launcher.launch();
instrumentation.addTransformer(new CustomAgentTransformer());
});
System.out.println("Waiting.....");
initTask.join();
}
我对这个问题感到困惑,感谢您的帮助。
【问题讨论】:
-
什么样的代理?没有代理快吗?什么是代理检测以及它是如何检测的?您是否已经使用分析器来找出时间花费在哪里?
-
感谢您的提醒。我修改了问题。应用程序快速启动,无需代理。但让我疑惑的是,在instrumentation之前执行代码时,类会需要很长时间才能加载。
-
使用模块化 java 可以部署一个没有 fat jar 的应用程序(也许还有你的自定义类加载器),如果没有人想出更好的理由来提高你的性能,我会尝试。
-
包含版本信息总是有帮助的......
-
感谢您的建议。我已经添加了 JDK 的版本信息以及有关该问题的更多描述。并且由于某种原因,我必须使用 jdk8 运行代码,并且无法使用 jdk 中的模块化。谢谢。
标签: java jvm classloader javaagents fatjar