[JVM 밑바닥까지 파헤치기] 7장 클래스 로딩 매커니즘
클래스 로딩
자바에서는 클래스 로딩, 링킹, 초기화가 모두 프로그램 실행 중에 이루어진다. 이 클래스 로딩을 거치기 때문에 실행 성능이 떨어지지만, 이를 통해 자바 애플리케이션의 확장성과 유연성을 보장할 수 있다.
이러한 동적 확장 언어 기능은 런타임에 이루어지는 동적 로딩 & 동적 링킹 덕분이다.
클래스 로더를 활용하면 실행 중인 프로그램 코드 일부를 바이너리 스트림으로 읽어올 수 있다.
- 클래스 파일 하나는 자바 언어에서의 클래스 혹은 인터페이스 하나를 지칭한다. (=타입)
클래스 파일
은 디스크 상의 특정 파일이 아니라 일련의 바이너리 스트림을 뜻한다.- 이 파일은 SSD, 네트워크, DB, 메모리 등 어디에도 존재할 수 있고 동적으로 생성되어도 무관하다.
클래스 로딩 시점
타입의 생애 주기는 로딩 -> 검증-> 준비 -> 해석 -> 초기화 -> 사용 -> 언로딩 과정을 거친다. 이 중 검증-> 준비 -> 해석 단계를 묶어 링킹 단계라고 한다. 이 중 로딩, 검증, 준비, 초기화, 언로딩은 반드시 순서대로 진행해야 한다. 해석 단계는 때에 따라 초기화 후에 시작할 수 있다. (런타임 바인딩 지원) 이 단계별 순서의 기준이 시작 시점임에 유의하자.
로딩 과정은 어떤 상황에서 시작하여도 무방하다.
반면, 초기화 단계는 즉시 시작해야 하는 상황 6가지를 엄격히 규정하였다. (= 타입에 대한 능동 참조)
new, getstatic, putstatic, invokestatic
을 만났을 때 해당 타입이 아직 초기화되어 있지 않다면 초기화- 리플렉션 메서드를 사용할 때 해당 타입이 아직 초기화되어 있지 않다면 초기화
- 클래스 초기화 시 상위 클래스가 초기화되어 있지 않다면 상위 클래스 초기화 (인터페이스 미해당)
- 가상 머신 구동 직후 사용자가 지정한 메인 타입(main() 메서드를 포함하는 클래스나 인터페이스)을 찾아 실행한다. 이때 메인 타입의 초기화를 먼저 시작한다.
java.lang.invoke.MethodHandle
인스턴스를 호출할 때 해당하는 클래스가 초기화되어 있지 않았다면 초기화- 인터페이스에 디폴트 메서드를 정의했다면, 해당 인터페이스 구현체 초기화 시 인터페이스부터 초기화
이에 해당하지 않는 모든 참조 방식은 수동 참조로 규정한다.
클래스 로딩 처리 과정
로딩
자바 가상 머신은 로딩 단계에서 다음 세가지 작업을 수행해야 한다.
- 완전한 이름을 보고 해당 클래스를 정의하는 바이너리 바이트 스트림을 가져온다.
- 바이트 스트림으로 표현된 정적인 저장 구조를 메서드 영역에서 사용하는 런타임 데이터 구조로 변환한다.
- 로딩 대상 클래스를 표현하는
java.lang.Class
객체를 힙 메모리에 생성한다. 이 Class 객체는 애플리케이션이 메서드 영역에 저장된 타입 데이터를 활용할 수 있게 하는 통로가 된다.
이 요구사항을 세세하게 명시하지 않았기 때문에, 가상 머신과 자바 어플리케이션의 구현을 보다 자유롭게 할 수 있었다.
그 덕분에, 다음과 같이 수많은 자바 기술들이 만들어 질 수 있었다.
- ZIP 압축 파일로부터 로딩
- 초기부터 흔히 쓰이던 방식
- 이후
JAR, EAR, WAR
형식의 기초가 된다.
- 네트워크로부터 로딩
- 웹 애플릿
- 런타임에 동적으로 생성
- 동적 프락시 기술.
java.lang.reflect.Proxy
의ProxyGenerator.generateProxyClass()
메서드는 지정한 인터페이스에 대해"$*Proxy"
형태의 프락시 클래스에 해당하는 바이너리 바이트 스트림을 생성한다.
- 다른 파일로부터 생성
- JSP 애플리케이션은 클래스 파일을 JSP 파일로부터 생성한다.
- 데이터베이스로부터 로딩(비교적 흔치 않음)
- SAP 넷위버(Netweaver) 같은 일부 미들웨어는 프로그램을 데이터베이스 안에 설치한 후 클러스터에 배포하는 방식을 제공한다.
- 암호화된 파일로부터 로딩
- 클래스 파일 디컴파일을 막기 위해 흔히 쓰이는 보호 조치다.
- 로딩 과정에서 클래스 파일을 해독하여 스누핑 공격으로부터 프로그램 로직을 보호한다.
로딩 단계가 끝나면 바이너리 바이트 스트림은 자바 가상 머신이 정의한 형식에 맞게 메서드 영역에 저장하고, 이후 타입 정보가 올바르게 저장되면 java.lang.Class
객체를 자바 힙에 초기화한다.
검증
링킹 과정 중 첫번째 단계로, 목적은 다음과 같다.
- 클래스 파일의 바이트 스트림에 담긴 정보가 자바 가상 머신 명세에서 규정한 모든 제약을 만족하는지 확인한다.
- 이 정보를 코드로 변환해 실행했을 때 자바 가상 머신 자체의 보안을 위협하지 않는지 확인한다.
가상 머신 명세
Leave a comment