2017-02-08 2 views
2

Я использую JavaCompiler для создания Java-класса, компиляции и загрузки в моем приложении.Почему JavaCompiler работает медленно при создании класса Java?

Моя проблема заключается в следующем: время выполнения с JavaCompiler намного медленнее, чем стандартный способ создания экземпляра того же класса.

Вот пример:

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 с тем же содержанием вара источником для тестирования производительности: это намного быстрее, чем путь JavaCompiler , (Я не могу использовать стандартный класс, потому что в моем приложении мне нужно его динамически создавать). Итак, можно ли улучшить производительность этого кода? Или эта низкая производительность в норме?

EDIT: сгенерированный код, который я также испытал это простая последовательность OWLAPI аксиом:

package myPackage; 

public class myClass{ 

static { 

myPackage.OWLMapping.manager.addAxiom(myPackage.OWLMapping.ontology, myPackage.OWLMapping.factory.getOWLSubClassOfAxiom(/*whatever*/); 
myPackage.OWLMapping.manager.addAxiom(myPackage.OWLMapping.ontology,myPackage.OWLMapping.factory.getOWLSubClassOfAxiom(/*whatever*/); 
myPackage.OWLMapping.manager.addAxiom(myPackage.OWLMapping.ontology,myPackage.OWLMapping.factory.getOWLSubClassOfAxiom(/*whatever*/); 


} 

} 

и это именно то, что переменная содержит источник. Число аксиом зависит от ввода пользователя.

+1

Используйте 'StringBuilder' для' source' для цикла while. Компилятор не оптимизирует конкатенацию в цикле. – 4castle

+0

@ 4castle Я сомневаюсь, что это сильно изменило бы ситуацию. – Kayaman

+0

Я не вижу, чтобы вы создавали экземпляр класса здесь. Имейте в виду, что когда ваш код должен писать источник, скомпилируйте его на байт-код и _then_ загрузите его, в то время как обычно вы делаете только последний шаг. –

ответ

1

У вас есть две области, которые могут быть медленными (но ваши тесты объединяют две области).

Первый заключается в создании Java String, который содержит исходный код. При добавлении строк в разные операторы JVM не может оптимизировать их в StringBuilder, что означает, что сначала он создает строку с одной стороны append, затем - String, а затем создает третий String, являющийся результатом двух прилагается. Это оказывает большое давление на сбор кучи и мусора, создавая множество объектов, которые почти сразу собирают мусор.

Чтобы устранить первую проблему, создайте StringBuilder и позвоните по номеру .append(...).

Вторая проблема заключается в том, что вы создаете JavaCompiler. Компилятор, используемый для компиляции Java-программ, может иметь один класс, управляющий его на верхнем уровне, но он будет использоваться в тоннах поддерживающих классов для заполнения его частных полей и встроенных включает. Наконец, при запуске этого объекта будет создано больше объектов для хранения кода: Lexer, Parser, AST of CompilationUnit и, в конечном счете, байтового кода. Это означает, что один строки кода

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
compiler.run(null, null, null, sourceFile.getPath()); 

, скорее всего, (опять же они не независимо друг от друга протестированных), чтобы занять некоторое время.

Наконец, линии загрузчика классов взаимодействуют с системой загрузки классов и могут плохо адаптироваться к производительности. Хотя это меньший шанс, что это большой успех, я бы тоже оценил эту линию самостоятельно.

Смежные вопросы