为什么JavaCompiler在实例化Java类时速度很慢?
我正在使用JavaCompiler动态创建一个Java类,编译它并加载到我的应用程序中 我的问题是:JavaCompiler的执行时间比实例化同一类的标准方法慢得多 这里有一个例子:为什么JavaCompiler在实例化Java类时速度很慢?,java,java-compiler-api,javacompiler,Java,Java Compiler Api,Javacompiler,我正在使用JavaCompiler动态创建一个Java类,编译它并加载到我的应用程序中 我的问题是:JavaCompiler的执行时间比实例化同一类的标准方法慢得多 这里有一个例子: static void function() { long startTime = System.currentTimeMillis(); String source = "package myPackage; import java.util.BitSet; public clas
static void function() {
long startTime = System.currentTimeMillis();
String source = "package myPackage; import java.util.BitSet; public class MyClass{ static {";
while (!OWLMapping.axiomStack.isEmpty()) {
source += OWLMapping.axiomStack.pop() + ";";
}
source += "} }";
File root = new File("/java");
File sourceFile = new File(root, "myPackage/MyClass.java");
sourceFile.getParentFile().mkdirs();
Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8));
// Compile source file.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());
// Load and instantiate compiled class.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });
Class<?> cls = Class.forName("myPackage.MyClass", true, classLoader);
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println("EXECUTION TIME: " + elapsedTime);
}
这正是变量源所包含的内容。
公理的数量取决于用户的输入。您有两个可能比较慢的区域(但您的基准测试将这两个区域结合起来) 第一个是构建包含源代码的Java
字符串。当跨不同的语句追加字符串时,JVM无法将它们优化到StringBuilder
s中,这意味着首先在追加的一侧创建字符串,然后在另一侧创建string
,然后在追加的两个语句中创建第三个string
。这给堆和垃圾收集带来了很大的压力,产生了大量几乎立即被垃圾收集的对象
要解决第一个问题,请创建一个StringBuilder
,并调用它的.append(…)
第二个问题是您正在实例化一个JavaCompiler
。用于编译Java程序的编译器可能有一个类在顶层驱动它,但它将从大量支持类中获取源代码,以填充其私有字段和嵌入的include。最后,当运行它时,将创建更多的对象来保存代码、词法分析器、解析器、编译单元的AST以及最终的字节码发射器。这意味着一行代码
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());
可能需要一些时间(同样,他们没有独立进行基准测试)
最后,类装入器行与类装入系统交互,可能对性能适应性较差。虽然这是一个较小的机会,它是一个大的性能打击,我也会基准线独立。使用StringBuilder
为源代码为While
循环。编译器没有优化循环中的串联。@4castle我怀疑这会有很大的不同。我没有看到您在这里实例化这个类。请记住,当您的代码必须编写源代码时,请将其编译为字节码然后加载,而通常您只执行最后一步。此外,请显示您的其他测试代码。您是否在问为什么编译类并加载它比使用预编译类慢?
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());