인프런 널널한 개발자 강사님의 기초 탄탄! 독하게 시작하는 Java - Part2 : OOP와 JVM의 강의 중 JVM내용 정리
Class Loader는 우리가 직접 만들수도 있다고 합니다. C/C++로 구현하지 않고 JAVA로도 직접 구현해서 사용할 수 있다고 하네요.
Class Loader에 대해 이해하기 위해 .class 파일과 바이트 코드에 대해 짚고 넘어갑니다.
.class 파일은 .java파일을 컴파일 했을때 생성되는 자바 바이트 코드입니다.
이것을 Class Loader가 Loading하는 것입니다. 윈도우로 치면 .exe, .dll 같은 확장자를 가진 실행파일(PE)이 JVM에서는 .class파일인 겁니다.
class 파일의 구조는 아래와 같다고 합니다.
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
위에서 부터
u4는 unsigned 캐릭터 아마 4바이트
밑으로 minor_version, major_version 정보가 나와있고
그 밑에 중요한 constant_pool_count 얘기가 나옵니다. 아무튼 이것저것 this class, super class, field, method, 이런정보가 담겨져 있구나 라는걸 알 수 있씁니다.
사진은 대표적인 Hello World! 코드를 컴파일한 .class 을 16진수 편집기로 열어본 것입니다.
맨 앞의 CA FE BA BE 이 4바이트가 위에서 u4에 해당하는 거고, 그 뒤로 major/minor 버전, constant pool 등등 정보가 담겨져 있는 것입니다. 근데 뭐 저거만 보고 리버스 엔지니어링을 하는 것은 힘들기 때문에 보통 도구를 이용해서
.class 파일을 분석하기도 한다고 합니다.
IntelliJ에서도 바이트코드를 볼 수가 있는데
바이트 코드 보는법은 생략하고 저런식으로 더 쉬운 형태로 변환하여 .class 파일을 분석할 수 잇다고 합니다.
저런 거로 디컴파일도 할 수 있다고 하네요.
아무튼
Hello World를 출력하는 .java 파일이 java byte code로 바뀌고 그걸 JVM이라는 프로세스가 실행시켜주는데,
근데 실질적으로 실행은 CPU가 하는 것입니다.
자바로 프로그램을 개발하게 되면 결국은 자바 소스코드 말고,
.class 파일에 들어있는 형태인 자바 바이트 코드의 스트림 형태로 변환이 되어서 로딩되고 적재된 다음에 어쩌구저쩌구 쭈욱 가는겁니다.
자바 바이트코드의 실행의 근거가 되어주는 것들은 JVM에서의 명령들입니다. 근데 JVM 자체가 가상 머신이지 진짜 머신(CPU)는 아닙니다. 그래서 결과적으로 그것들(바이트코드들)을 CPU가 인식할 수 있는 Native코드로 바꾸어 주어야 합니다. 그래서 그 과정에서 사용되는 컴파일러가 등장합니다. 그래서 컴파일러가 두 번 등장하는데
첫 번째로, .java파일을 .class 파일로 바꾸는 컴파일러.
두 번째로, .class파일을 CPU가 이해할 수 잇는 Native 코드로 바꾸는 컴파일러
네이티브로 바꿔주는 컴파일러는 두 놈이 있습니다.
JVM의 3가지 영역 중 Execution Engine에 해당되는 부분에서 Interpreter와 JIT Compiler 입니다.
JIT컴파일러(Just-In-Time) 는 JVM이 바이트코드 레벨에서 분석을 해서 예를들어 반복문을 돈다고 하면 반복문 안의 코드는 특정 횟수 만큼 반복이 될 것입니다 이런 반복되는 부분에대해 JIT가 미리 컴파일을 해놓습니다.
평상시에는 Interpreter가 바이트코드를 일정 단위 뜯어와서 CPU에 번역해서 연산시키고 합니다. 근데 이걸 매번 변환하는 과정을 거친다는 것은 성능을 떨어뜨리는 원인이 됩니다.
그래서? JIT가 자주 사용되는 부분을 미리 번역해놓고 재사용하기 때문에 JIT로 인해 JVM의 성능이 극단적으로 상승했다고 합니다.
Class Loader
클래스로더의 역할을 생각해보면 하는 일도 많고 중요하기도 하지만 생각보다 이걸 건드리거나 할 일은 많이 없다고 합니다. 따라서 클래스로더가 무슨일을 하는지 이론적으로만 알아도 된다고 합니다.
우리가 작성한 JAVA파일을 class 파일로 컴파일이 되고, class파일 안에 있는 자바 바이트코드를 JVM이 뜯어와서 실행을 하게 됩니다.
중요한 점은 바이트 코드의 본질은 결국에는 Method라는 것입니다.
클래스 로더가 하는 일은 아래와 같습니다.
1. 이름을 알고 있는 특정 클래스에 대한 정의(Byte Stream)를 가져오는 역할을 수행
-> 가져온다라는 의미를 생각해 보면 어디 다른곳에서 가져올 수 있다는 의미입니다. 네트워크를 통해 퍼온다거나 할 수 있습니다.
2. 부트스트랩 클래스 로더
- JVM에서 라이브러리로 취급(rt.jar, tools.jar)되는 것들을 로드 (핫스팟에서는 C++로 구현)
3. 플랫폼 클래스 로더 (기존 확장 클래스 로더)
- 클래스 라이브러리 로드
4. 애플리케이션 클래스 로더
- sun.misc.Launcher$AppClassLoader를 의미
클래스가 로딩되는 과정
개발자에게는 3가지 시점이 있습니다.
1. 컴파일타임
2. 링크타임
3. 런타임
그런데 자바에서는 이렇게 구분하는 개념이 없습니다. build를 하면 컴파일타임을 말하고 실행을 하면 링크 + 런타임을 묶는다고 합니다.
그래서 클래스를 로딩하겠다 하면 JVM이 인식할 수 있게 하는 자바 바이트코드 스트림 덩어리로 바꾸는 과정을 로딩 단계라고 합니다. 위 그림에서는 Loading -> Linking 까지 입니다.
그리고 사용단계는 그 아래쪽인데 사용단계 수준에서 인스턴스화를 진행합니다. 즉, new 연산이 등장하는거죠 그래서 Using 박스 안에 Initializaion(초기화) 가 있는 것입니다.
그리고 Unloading은 GC를 통해 메모리가 해제되는 것입니다.
Java 클래스 로딩
- 클래스 로딩 및 링킹 과정이 모두 런타임에 이루어짐
- 실행 성능이 일부 저하될 수 있으나 높은 확장성과 유연성을 제공하는 근간
- 인터페이스만 맞으면 Runtime에 구현 클래스를 결정하지 않을 수 잇음
- 클래스 로더는 실행할 프로그램 코드를 네트워크로 수신하는 것도 가능
- 해석(Resolution) 단계는 동적 바인등(혹은 늦은 바인딩)을 지원할 목적으로 초기화 후로 지연될 수 있음
로딩 단계에서 가장 먼저 하는일, 검증.(Verification)
- JVM 명세가 정하는 규칙과 제약을 만족하는지 확인합니다.
- 파일 형식(.class)
- 메타데이터
- 바이트코드
- 심벌 참조
- 보안위협에 대한 검증 포함
- 바이트코드 검증 시 함께 확인
준비 및 해석단계(Preparation, Resolution)
- java.lang.Class 인스턴스(메타 데이터)가 힙 영역에 생성되고 클래스 변수(정적 멤버) 메모리를 0으로 초기화
-> 로드되는 클래스의 인스턴스는 Using 단계에서 힙 사용
-> final 선언된 변수는 코드에서 정의한 초깃값으로 정의(0이 아닐수 있다)
- 생성자 호출 전 상태(new 연산 전 단계)
-> 필드(인스턴스 변수) 초깃값은 생성자 호출 시 정의됨
-> 정적 필드에 초깃값 할당
- 해석은 상수 풀의 심벌 참조를 직접 참조로 대체하는 과정
사용단계
Heap 영역에 객체 생성 (new 연산 실행)
- JVM은 객체 저장을 위한 메모리 공간을 확보 후 0으로 초기화 (단, 객체 헤더 제외)
- 객체 초기화를 위한 구성설정 실시
-> 클래스 이름 및 메타 정보 확인 방법
-> 객체에 대한 해시코드
-> GC 세대 나이
- 생성자 호출
'CS > JAVA' 카테고리의 다른 글
JVM 이해하기 (1) - 도입 (3) | 2025.01.28 |
---|---|
옵저버 패턴 정리 (0) | 2024.07.21 |