💡이전에 Java Memory Layout과 Garbage Collection, 그리고 compiler에 대해 알아보며 간단히 JVM 공부를 해보았지만, (당연하게도)여전히 Java architecture의 모든 기능들이 구체적으로 명확히 그려지지가 않았다. 하여 좀 더 디테일한 참고자료를 찾고자 하였지만 국내에 JVM이라는 주제에 대해서만 다룬 책은 구하기가 어렵거나 선택의 폭이 너무 좁아, 해외의 'Inside the Java 2 Virtual Machine'이라는 원문 책을 구해 시간날 때마다 추가로 조금씩 읽어보며 배운 점이나 재미있던 내용을 중심으로 포스팅해보려고 한다.
(주의할 점은 이 책의 발행일이 2000년이라는 점으로, 20년이 더 지난 책이므로 발행 당시의 컴퓨터나 네트워크 등의 기술환경 맥락이 현재와는 많이 다를 수 있다는 점을 염두에 두었다)
보통 "Java"라고 하면 사람들은 주로 언어 자체를 지칭하지만, 사실 Java 언어는 Java 기술 생태계의 일부일 뿐이며 JVM, Java API, Java class file work를 모두 하나로 이해함이 옳다.
Java가 만들어진 배경 당시에는, 네트워크가 활성화되고 그에 연결된 마이크로프로세서를 장착한 수 많은 종류의 디바이스들이 본격적으로 상용화되기 시작하고 있었으며, 당시에 Java의 야심은 이런 다양한 디바이스들 모두(?)에서 platform에 종속적이지 않은 개발환경을 제공하는 것이었던 것 같다.
특히 Java는 네트워크 환경을 염두에 두고 디자인 되었다. 네트워크로 연결된 환경을 중점적으로 염두에 둔 디자인은 Java architecture 구석구석에서 발견될 수 있다.
자바 플랫폼이 설치되있는 어디에서든 자바 프로그램은 동작할 수 있다. JVM은 가상 컴퓨터이며, Java 바이트코드를 실행할 수 있어야 한다(바이트코드를 실행만 할 수 있으면 어떤 형태로든 OK). JVM의 주 임무는 class 파일들을 로드하고 그 안의 bytecode를 실행하는 것며, 'class loader'는 프로그램과 Java API로 부터 class 파일들을 로드하고, bytecode의 실행은 'execution engine'이 맡는다.
execution engine은 다양한 형태로 구현될 수 있다. 가장 단순히는 bytecode를 한 번에 한 줄씩 해석(interpret)하거나, 'just-in-time(JIT) compiler'와 같이 메모리는 더 많이 사용하지만 빠른 execution engine도 있다.
JIT compiler는 런타임에서 어떤 메서드가 처음 호출되면 기계 원어로 번역을 하고 해당 기계 원어를 캐시(cache)하며, 해당 기계 원어로 된 메서드는 다음에 또 호출될 시 번역과정 없이 바로 재사용될 수 있어 빠르다.
Java 프로그램은 Native methods를 호출함으로써 호스트 OS와 상호작용을 하기도 한다. Java에는 두 종류의 메서드가 있는데, Java와 Native 메서드이다. Java 메서드는 바이트코드로 번역되어 class files에 저장되며, Native 메서드는 C나 C++, 어셈블리어 등으로 작성돼있고 특정 프로세서에 맞는 특정 기계어로 번역되어 동적으로 연결된 라이브러리(dynamically linked library)에 저장된다. Java 메서드는 플랫폼 독립적이며, Native 메서드는 그렇지 않다. Native 메서드는 자바 프로그램과 그 기저의 OS를 연결한다고 볼 수 있다.
Native 메서드 사용 시 기저 OS의 자원에 직접 접근할 수 있으나, 이런 방식은 플랫폼에 특정되게 되고, 프로그램이 한 가지 Java Platform 구현에 특정(Vendor들마다 Java Platform의 구현이 다름)되는 결과를 낳을 수 있다. Java Native Interface(JNI)는 이런 Native 메서드들이 어떤 Java Platform의 구현에 종속되지 않도록 한다. 하지만 Vendor들은 JNI를 지원하도록 강제되지는 않으며, 각자 입맛에 맞게 Native 메서드 인터페이스를 제공할 수도 있다.
Java 코드로 작성만 하면 JVM이 설치된 어떤 운영체제-HW에서든 실행할 수 있다는 것은 좋다. 그렇기 때문에 디바이스와 운영체제를 만드는 Vendor들에게 각자 필요에 맞게 유연하게 JVM을 구현할 수 있도록 설계를 하고 친절히(?) spec을 명시해둔 것 같지만...결국 JVM 자체를 다양한 운영체제와 HW에 맞게 각각 구현해야 할텐데 세상에 그 많은 디바이스들을 커버할 수 있는 수많은 버전의 JVM을 구현한다는 게...🥲