JVM의 구성요소
Class Loader
Class Loader는 바이트코드(.class)를 읽어들여서 클래스 객체를 생성하는 역할을 담당한다. class 로딩은 Run-Time에 일어난다.
개발자가 new라는 예약어로 객체를 생성하는 코드를 처음 실행할 때 JVM은 만들 클래스를 Class Loader로 .class 파일을 최초로 메모리에 load한다. 최종적으로 Runtime Data Area의 Method Aread에 배치된다.
Class Loader의 기술적 특징
- Hierarchical : Class Loader 간에 계층형 구조를 가짐. 'bootstrap' Class Loader가 가장 최상위
- Delegate load reqeust : 계층형 구조를 가지고 있어 어느 시점에 Class 로딩요청을 받으면 상위 Class Loader가 로딩한 클래스가 우선권을 가짐
- Have visibility constraint : 자식 Class Loader는 부모 Class Loader를 찾을 수 있지만 그 반대는 불가
- Cannot unload classes : Class Loader에 의해 로딩된 클래스들은 unload될 수 없음
Class Loader delegation model
로딩 요청을 위계적응로 전달하는 방식을 나타내는 것으로 class를 로딩할 때 자신의 Class Loader의 위계 구조의 위쪽인 부모 Class Loader에게 로딩을 위임하는 것이다.
Class Loader의 위계 구조는 Bootstrap - Extension - Application 구조를 가진다.
Class Loader들이 class를 로딩하면 되면 하나의 delegation parent와 함께 생성되고, Cache-Parent-Self의 순서로 해당 클래스를 확인한다. 로딩하게 될때 가장 먼저 class가 이미 로딩이 되어 있는지 확인해
- 로딩이 되어 있다면 메모리에 Cache되어 있을 것이고 이 경우엔 해당 class를 반환한다.
- 로딩되어 있지 않았다면 부모에게 class를 로딩하게 위임하고 부모가 위임할 수 없다면 자신이 클래스를 탐색한다.
로딩할 확률은 delegation model의 상위로 갈 수록 높아지고, 최상위 Class Loader인 bootstrap class loader는 JVM의 수행을 위한 핵심적인 class만을 로딩하게 되고 가장 기본적인 class들의 버전이 일치하는지 확인하고 각 class가 누구에 의해 로딩이 되었는지에 대한 정보를 제공한다. Have visibility constraints 특징에 의해 상위에서 하위의 loader가 로딩한 정보를 알 수 없다.
Bootstrap Class Loader
다른 Class Loader들과는 달리 boostrap Class Loader는 자바 코드에 의해 instance화 될 수 없다.
Boot ClassPath에서 핵심 시스템 class들을 로딩하는데 일반적으로 JavaHome의 jre/lib 디렉토리에 있는 JAR 파일들이다.
단 -Xbootclasspath 옵션으로 class path를 추가, 수정할 수 있다.
Native C로 구현되어 있어 String.class.getClassLoader()는 그냥 null을 반환한다. Primordial Class Loader라고 부르기도 한다.
Extension Class Loader
주로 jre/lib/ext 디렉토리나 java.ext.dirs 환경변수로 지정된 폴더에 있는 클래스 파일을 로딩한다. 자바로 구현되어 있으며 sun.misc.Launcher 클래스 안에 static 클래스로 구현되어 있고 URLClassLoader를 상속한다.
Application Class Loader
-classpath(또는 -cp)나 JAR 파일 안에 있는 Mainfest 파일의 Class-Path 속성값으로 지정된 폴더에 있는 클래스를 로딩한다.
자바로 구현되어 있고, sun.misc.Launcher 클래스 안에 static 클래스로 구현되어 있으며, URLClassLoader를 상속하고 있다.
개발자가 애플리케이션 구동을 위해 직접 작성한 대부분의 클래스는 Application Class Loader에 의해 로딩된다.
Class Loading의 단계
1. Loading : 필요한 class file을 배치하고 바이트 코드를 loading
2. Linking : 바이트코드가 정상적으로 작동하는지 확인하고(Verify), class에서 정의된 변수, 메소드, 인터페이스들을 나타내는 데이터 구조를 준비하며(Prepare), class에 다양한 방식으로 참조된 모든 class를 loading(Resolve)
3. Initializing : class내에 포함된 정적인 변수나 메소드를 초기화
Explicit Loading vs Implicit Loading
Explicit Loading은 (java.lang.ClassLoader).loadClass() 나 Class.forName() 메소드 중 하나를 사용하여 로딩될 때 발생한다. 이러한 메소드가 호출되면 이름이 인자로 지정된 클래스가 Class Loader에 의해 로딩된다. 메소드를 호출하지 않으면 그냥 delegation model을 따라 클래스를 로딩한다.
Implicit Loading은 클래스가 레퍼런스, 인스턴스화, 명시적 메소드 호출을 제외한 상속의 경우 로딩되는 방식으로 로딩작업은 초기화되고, JVM은 필요한 레퍼런스를 결정해 로딩이 되어 있으면 레퍼런스만 리턴, 안되어 있으면 delegation model을 따라 클래스를 로딩한다.
Execution Engine
JVM은 Method Area의 바이트코드들을 Execution Engine에 제공하여 클래스에 정의된 내용대로 바이트코드를 실행시킨다. 이때, Load된 바이트 코드를 실행하는 Runtime Module이 Execution Engine이다.
Exceution Engine 실행 방식
바이트 코드를 명령어 단위로 읽어서 실행하는데 두 가지 방식을 혼합하여 사용한다.
1. Interpreter 방식
바이트 코드를 한 줄 씩 해석, 실행하는 방식이다. 초기 방식으로, 속도가 느리다는 단점이 있다.
2. JIT(Just In Time) 컴파일 방식 또는 동적 번역 (Dynamic Translation)
바이트 코드를 JIT 컴파일러를 이용해 프로그램을 실제 실행하는 시점(바이트코드를 실행하는 시점)에 각 OS에 맞는 Native Code로 변환하여 실행속도를 개선했다. 하지만, 바이트 코드를 Native Code로 변환하는 데에도 비용이 들어 JVM은 Interpreter 방식을 사용하다가 일정 기준이 넘어가면 JIT 방식을 사용한다.
JIT 컴파일러는 같은 코드를 매번 해석하지 않고, 실행할 때 컴파일을 하면서 해당 코드를 caching해 이후에 바뀐 부분만 컴파일하고 나머진 caching된 코드를 사용한다.
Garbage Collector(GC)
더이상 사용하지 않는 인스턴스들을 삭제하는 역할을 수행한다.
GC는 Heap 영역에서 사용하지 않는 객체들을 제거하는 작업을 총칭한다. 자바는 개발자가 메모리를 직접 해제해줄 수 없는 언어이기 때문에 GC로 자동으로 해제해준다.
참고 자료
https://dev-jj.tistory.com/entry/JAVA-JVM의-구성요소-및-동작원리
https://performeister.tistory.com/4
https://homoefficio.github.io/2018/10/13/Java-클래스로더-훑어보기/
'공부 > Java' 카테고리의 다른 글
[공부/Java] static이란? (0) | 2022.12.28 |
---|---|
[공부/Java] JVM, JRE, JDK (0) | 2022.12.24 |
[공부/Java] 자바의 main() 메소드, 예외, 예외 처리, try-catch-finally, 예외 클래스 (0) | 2022.07.11 |
[공부/Java] 자바의 배열, 선언, 생성, 초기화, 인덱스, 치환, 공유, 크기, for-each문, 리턴 (0) | 2022.07.11 |
[공부/Java] 자바 키보드 입력 - Scanner (0) | 2022.07.04 |