JVM에 클래스 파일(.class)을 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.
Class Loader에서는 클래스 로딩(Loading), 링크(Linking), 초기화(Initalization) 순으로 클래스 파일을 메모리에 할당한다.
먼저 클래스 로딩은 클래스를 읽어오는 과정이다. 클래스 로더가 .class 파일을 읽고 내용에 맞는 Binary 데이터를 생성하여 Method 영역에 저장한다.
이후 링크 과정에선 heap 영역에 저장된 객체를 가지고 오는 과정을 수행한다.
예를 들어 Book 클래스의 객체를 생성할 때, Method 영역에서 Book 클래스에 대한 정보를 가지고 와 클래스 정적 변수에 대한 값을 초기화한다. 이렇게 만들어진 객체와 선언한 객체 이름을 연결시키는 과정이다.
즉, 클래스 자체에 대한 정보는 Method 영역에 올라가고, Method 영역에 올라간 Class에 대한 객체를 생성할 때는 Method 영역에서 클래스에 대한 정보를 가지고 와서 객체를 만들고, 만든 객체를 Heap 영역에 저장하는 것이다.
마지막으로 초기화 과정을 정하는데, static으로 선언된 변수와 메소드에 대해 메모리를 할당하고 초기 값을 채우는 과정이라고만 이해하면 된다.
(static이 아닌 일반 클래스는 로딩 및 링크 과정에서 메모리가 할당됨)
JAVA에서는 한 번에 모든 클래스를 로드하지 않고 Runtime 시에 클래스를 로드한다.
즉, 클래스를 "처음" 참조할 때 해당 클래스를 로드하여 링크하는 과정을 거치는 것이고, 이 역할을 클래스 로더가 수행하는 것이다.
클래스를 실행시키는 역할이다. 클래스 로더가 Runtime Data Area에 Byte Code를 배치시켰다면 이 Code를 Execution Engine을 통해 실행하는 것이다.
이때 2가지 방식을 활용한다.
JIT 방식으로 Native Code로 만든게 빠르다면 인터프리터 방식 대신 JIT만 활용하는 게 더 좋을 수 있다고 생각할 수 있다.
하지만 문제는 Byte Code를 Native Code로 "컴파일" 해야 한다는 점이다. 당연히 컴파일하는 데에도 시간이 소요되며, 컴파일하는데 소요되는 시간은 Byte Code를 인터프리팅하는 것보다 훨씬 오래 걸린다.
따라서, 한 번만 실행되거나 몇 번 실행되지 않는 코드라면 그냥 인터프리팅하는 것이 유리하다.JIT Compiler를 활용하는 JVM은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크하여 일정 수준 이상으로 활용될 경우에만 컴파일을 수행하여 JIT 기법을 활용하게 된다.
GC를 수행하는 모듈(Thread)가 존재한다.
Garbage Collector 같은 경우 나중에 이 개념에 대해서 설명할 기회가 있을 것이다.
Runtime Data Area는 프로그램을 수행하기 위해 JVM이 OS에서 할당받은 메모리 공간이다.
JVM이 가상머신이라고 했는데, 가상 머신은 OS에서 메모리를 할당받아 이를 물리적 컴퓨터가 존재하는 것처럼 구현하는 Software이다.
Runtime Data Area가 실제로 메모리를 할당받아 가상 머신 역할을 하는 공간이라고 생각하면 된다.
Thread가 시작될 때 생성되며, Thread마다 1개씩 존재한다.
Thread가 어떤 부분을 실행해야 할지에 대한 기록을 하는 부분으로, 현재 수행 중인 JVM 명령의 주소를 가진다.
프로그램 실행 과정에서 임시로 할당되었다 메서드를 빠져나가면 바로 소멸되는 특성의 데이터를 저장하기 위한 영역이다.
즉, 전체 명령을 수행하는데 다시는 볼 필요 없는, 그 메서드에만 특별히 사용되는 지역 변수를 위한 공간이다.
메서드 수행이 끝나면 Frame 별로 삭제를 하며, C언어의 메모리 공간처럼 매개변수, 지역변수, Return 값 및 연산 시 일어나는 값들도 임시로 저장한다.
(C언어의 메모리 Stack과 유사하다고 보면 된다)
JAVA ByteCode가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행하기 위한 영역으로, JAVA가 아닌 다른 언어로 작성된 코드를 위한 공간이다.
Class Area, Static Area라고도 부른다.
클래스 정보를 처음 메모리 공간에 올릴 때 초기화되는 대상을 저장하기 위한 메모리 공간이다.
이 공간에는 Runtime Constant Pool이라는 별도 관리 영역이 존재한다.
여기에는 상수 자료형을 저장하여 참조하고 중복을 막는 역할을 수행한다.
즉, Method Area에 클래스에 대한 정보가 저장되며, 클래스 내부에 존재하는 메서드들도 바이트코드 형태로 저장된다.
또한 상수 자료형은 Runtime Constant Pool에 저장하여 메서드를 수행할 때 중복된 상수 자료형이 나오지 않도록 따로 관리하는 것이다.
Method Area는 Heap Area와 마찬가지로 GC(Garabage Collector)의 관리 대상에 포함되며, 아래 3가지 정보 종류가 저장된다.
Method Area에서 클래스 및 멤버 변수, 메서드를 바이트 코드 형태로 저장했다고 하면 Heap Area는 저장된 정보를 바탕으로 객체를 생성한 이후 생성한 객체를 저장하는 가상 메모리 공간이라고 생각하면 될 것이다.
Runtime Data Area 구조를 자세히 보면 알겠지만, Heap Area와 Method Area는 공유되고 있음을 알 수 있다. 따라서, 여러 Thread에서 같은 객체에 접근할 수 있다는 점에 주의해야 하겠다.
무조건 Method Area 영역에 올라온 클래스들로만 객체로 생성할 수 있다.
이 Heap Area가 GC(Garabage Collection) 동작 과정에서도 큰 부분을 차지하기 때문에, 어떤 영역인지 이해하고 GC를 배울 때 더 자세히 구조에 대해 설명하기로 하겠다.
자바 플랫폼은 'API와 가상머신'으로 구성되어 있다.
특정 자바 프로그램이 실행되는 환경을 자바 플랫폼이라고 하며, 대표적으로 JAVA SE, JAVA EE, JAVA ME, JAVA Card 등이 존재한다.
실행환경에 따라 API 구성 등이 달라지는 것이 특징이라고 할 수 있다.
JAVA SE는 일반적인 목적으로 활용되는 자바 플랫폼이며, JAVA EE는 대규모 개발을 위한 기업 수준의 개발을 위해 활용되는 플랫폼이다.
최근에는 Spring 및 오픈소스 프레임워크의 성장으로 인해 JAVA EE 시장이 축소되었고, 사실상 JAVA SE만을 사용한다고 봐도 무관하다.
JAVA는 javac.exe를 통해 컴파일을 수행하여 Java Bytecode를 생성하고(.class 파일), 이렇게 만들어진 파일을 java.exe를 통해 인터프리터 과정이 수행되어 JVM 상에서 바이트 코드가 수행된다.
JVM은 자바 가상 머신으로 Java Bytecode를 해석하여 OS에 실행할 수 있게 번역해주는 가상 머신이다. Class Loader와 자바 API를 함께 실행시켜 최종적으로 코드를 수행하는 역할을 하며, OS에 독립적으로 수행될 수 있게 하는 1등 공신이다.
JVM은 OS에서 메모리를 할당받고, 컴파일 된 Java Bytecode(클래스 파일)을 받는다. Class Loader는 클래스 파일을 JVM에 로딩하는데, 클래스에 대한 정보는 Method Area에 저장되게 될 것이다.
이후 Execution Engine을 통해 코드가 실행될 텐데 이 과정에서 Interpreter 방식과 JIT, 2가지 방식을 혼합 활용하여 기계가 실행할 수 있는 형태로 Bytecode를 변형시킨다.
최종적으로 해석된 코드는 Runtime Data Areas에 배치되어 객체 생성 시 Heap Area에 해당 객체를 저장하면서 실질적인 코드 수행이 이루어지게 될 것이다.
Runtime Data Access 공간에서는 Thread가 추가될 때마다 PC Register가 생성되어 JVM에서 실행하는 명령 주솟값이 저장될 것이며, 메서드 내의 지역 변수 등은 JVM Stack 영역에 저장되어 Thread가 실행될 것이다.
Method Area에는 클래스 및 클래스 내부 메서드, 멤버 변수가 저장되어 있을 것이며 이렇게 저장된 정보를 활용해 객체를 형성하여 생성된 최종 객체를 Heap Area에 저장함으로써 객체를 활용할 수 있게 되는 것이다.
JDK는 자바 개발 도구로써, JAVA Code를 실행시키기 위해 필요한 도구이다. JRE는 자바 실행 환경으로써 Bytecode가 주어진다면 바로 "실행"은 시킬 수 있게 된다. JDK도 자바를 실행시켜 결과물을 볼 필요가 있으므로 JRE를 포함하고 있다.