2017-02-08 1 views
2

JavaCompiler를 사용하여 동적으로 Java 클래스를 작성하고 컴파일하고 응용 프로그램에로드합니다.Java 클래스를 인스턴스화하는 동안 JavaCompiler가 느린 이유는 무엇입니까?

내 문제는 다음과 같습니다. JavaCompiler의 실행 시간이 동일한 클래스를 인스턴스화하는 표준 방법보다 훨씬 느립니다. 여기

예 : 그것이하여 JavaCompiler 방법보다 훨씬 빠릅니다 :이 코드를 측정 한 후, 나는 성능을 테스트하기 위해 VAR 소스 같은 내용으로 새로운 자바 클래스를 생성

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); 
    } 

. (표준 클래스를 사용할 수없는 이유는 응용 프로그램에서 동적으로 만들어야하기 때문입니다.) 그럼이 코드의 성능을 향상시킬 수 있습니까? 아니면이 낮은 성능은 정상입니까?

편집 : 나는 또한 테스트 생성 된 코드는 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

'while' 루프의'source'에'StringBuilder'를 사용하십시오. 컴파일러는 루프에서 연결을 최적화하지 않습니다. – 4castle

+0

@ 4castle 나는 이것이 많은 차이를 만들지는 모르겠다. – Kayaman

+0

나는 여기서 클래스를 인스턴스화하는 것을 실제로 보지 않는다. 코드가 소스를 작성해야 할 때 바이트 코드로 컴파일하고 _then_로드해야하며 일반적으로 마지막 단계 만 수행합니다. –

답변

1

속도가 느릴 수있는 두 영역이 있지만 벤치 마크가 두 영역을 결합합니다.

첫 번째는 소스 코드가 포함 된 Java String을 작성하는 중입니다. 서로 다른 명령문에 문자열을 추가 할 때 JVM에서는 이들을 StringBuilder으로 최적화 할 수 없습니다. 즉, 추가 문자열의 한쪽에 문자열을 작성한 다음 다른 문자열에 String 문자열을 작성한 다음 두 번째 문자열에서 세 번째 String을 생성합니다. 추가됨. 이것은 힙 및 가비지 콜렉션에 많은 부담을 주며 거의 즉시 가비지 수집되는 많은 오브젝트를 생성합니다.

첫 번째 문제를 해결하려면 StringBuilder을 만들고 .append(...)이라고 부릅니다.

두 번째 문제점은 JavaCompiler을 인스턴스화하는 것입니다. Java 프로그램을 컴파일하는 데 사용되는 컴파일러는 최상위 레벨에서이를 구동하는 하나의 클래스를 가질 수 있지만 해당 클래스를 지원하는 여러 클래스에서 소스를 가져와 개인 필드와 포함 된 포함을 채 웁니다. 마지막으로,이를 실행하면 코드, Lexer, Parser, CompilationUnit의 AST 및 결국 바이트 코드 이미 터를 보유하는 더 많은 오브젝트가 작성됩니다. 이

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

코드

의 한 라인이 약간의 시간이 걸릴 (다시 그들이 독립적으로 벤치마킹되지 않음) 가능성이 있다는 것을 의미한다.

마지막으로 클래스 로더 행은 클래스 로딩 시스템과 상호 작용하며 성능에 적합하지 않을 수 있습니다. 작은 기회 일지라도 큰 성과를 올렸지 만, 나는 그 라인을 독립적으로 벤치마킹 할 것입니다.

관련 문제