[java] JVM이 JIT 컴파일 된 코드를 캐시하지 않는 이유는 무엇입니까?

Sun의 표준 JVM 구현은 코드가 몇 번 실행 된 후 거의 네이티브 실행 속도를 얻기 위해 바이트 코드에 매우 정교한 최적화를 적용합니다.

문제는 왜이 컴파일 된 코드가 동일한 함수 / 클래스의 후속 사용 중에 사용하기 위해 디스크에 캐시되지 않는 것입니까?

현재로서는 프로그램이 실행될 때마다 JIT 컴파일러가 미리 컴파일 된 코드 버전을 사용하지 않고 새로 시작됩니다. 이 기능을 추가하면 바이트 코드가 본질적으로 해석 될 때 프로그램의 초기 실행 시간이 크게 향상되지 않습니까?



답변

@MYYN이 게시 한 링크의 잘라 내기 및 붙여 넣기에 의존하지 않고, 이는 JVM이 수행하는 최적화가 데이터 패턴과 코드 패턴을 기반으로하는 정적이 아니라 동적이기 때문이라고 생각합니다. 이러한 데이터 패턴은 애플리케이션의 수명 동안 변경되어 캐시 된 최적화가 최적 수준보다 낮을 수 있습니다.

따라서 저장된 최적화가 여전히 최적인지 여부를 확인하는 메커니즘이 필요합니다.이 시점에서 즉시 다시 최적화 할 수 있습니다.


답변

오라클의 JVM 은 실제로 문서화되어 있습니다.

컴파일러는 Oracle JVM의 클래스 분석 모델을 활용하여 데이터베이스 호출, 세션 또는 인스턴스에서 컴파일 된 Java 메소드를 선택적으로 지속 할 수 있습니다. 이러한 지속성은 의미 상 Java 코드가 변경되지 않은 것으로 알려진 세션 또는 인스턴스간에 불필요한 재 컴파일의 오버 헤드를 방지합니다.

모든 정교한 VM 구현이 유사한 옵션을 제공하지 않는 이유를 모르겠습니다.


답변

기존 답변에 대한 업데이트-Java 8에는이를 해결하기위한 JEP가 있습니다.

=> JEP 145 : 캐시 컴파일 된 코드 . 새 링크 .

매우 높은 수준에서 명시된 목표는 다음과 같습니다.

대규모 Java 애플리케이션의 시작 시간을 개선하기 위해 이전 실행에서 컴파일 된 원시 코드를 저장하고 재사용합니다.

도움이 되었기를 바랍니다.


답변

Excelsior JET 에는 2001 년에 릴리스 된 2.0 버전부터 캐싱 JIT 컴파일러가 있습니다. 또한 AOT 컴파일러는 모든 최적화를 사용하여 캐시를 단일 DLL / 공유 개체로 다시 컴파일 할 수 있습니다.


답변

JVM 구현에 어떤 식 으로든 관여하지 않는 실제 이유를 모르지만 몇 가지 그럴듯한 이유를 생각할 수 있습니다.

  • Java의 아이디어는 write-once-run-anywhere 언어이며, 클래스 파일에 미리 컴파일 된 내용을 넣는 것은 일종의 위반입니다 (물론 실제 바이트 코드가 여전히 존재하기 때문에 “종류”만 있음).
  • 동일한 코드를 여러 번 사용하기 때문에 클래스 파일 크기가 증가합니다. 특히 여러 다른 JVM에서 동일한 프로그램을 실행하는 경우 (다른 버전을 다른 JVM으로 간주 할 때 실제로 드물지 않습니다. 정말해야합니다)
  • 클래스 파일 자체는 쓰기가 불가능할 수 있습니다 (확인하기가 매우 쉽습니다).
  • JVM 최적화는 부분적으로 런타임 정보를 기반으로하고 다른 실행에서는 적용 가능하지 않을 수 있습니다 (여전히 약간의 이점을 제공해야 함).

하지만 저는 정말로 추측하고 있습니다. 보시다시피 제 이유 중 어떤 것도 실제 쇼 스토퍼라고 생각하지 않습니다. 나는 Sun이이 지원을 우선 순위로 생각하지 않는다고 생각하며, 습관적으로이 작업을 수행하면 사람들이 Java 클래스 파일이 실제로 각 VM에 대해 별도의 버전이 필요하다고 생각하게 할 수도 있기 때문에 내 첫 번째 이유가 진실에 가깝다고 생각합니다. 크로스 플랫폼.

내가 선호하는 방법은 실제로 이와 같은 작업을 미리 명시 적으로 수행하는 데 사용할 수있는 별도의 바이트 코드-네이티브 변환기를 사용하여 특정 VM에 대해 명시 적으로 빌드 된 클래스 파일을 생성하는 것입니다. 다른 VM에서도 실행할 수 있습니다. 그러나 그것은 아마도 내 경험에서 비롯된 것 같습니다. 저는 대부분 Java ME를 해왔는데, Java 컴파일러가 컴파일에 대해 더 똑똑하지 않다는 점이 정말 아픕니다.


답변