-
[Java] JVM 이 무엇인지, 어떻게 작동하는지 대충 훑어보자! (feat. 클래스로더)프로그래밍 언어/Java 2022. 5. 29. 17:44
싱글톤패턴 중
Initialization on demand holder idiom
라는 구현 기법이 있는데
해당 기법은 JVM 의 클래스로더 매커니즘을 이용한 방식이라 한다.
스프링을 사용할 때도 종종ClassNotFoundException
이 터질 때,
검색을 해보면 클래스로더라는 키워드가 종종 등장한다.
리플렉션도 클래스로드라는 키워드가 항상 같이 끼워팔리고 있다.
그렇다 나는 미뤄왔다... 습득해야되지만 귀찮다는 이유로...
이제는 지식의 부채의 상환일이 다가 온 것이다... ㅠ_ㅠ
(하지만 대충 볼거야)# 용어정리
1. JVM (Java Virtual Machine)
개요
자바 바이트 코드(
.class
파일)를 OS에 특화된 코드로 변환하여 실행하는 역할을 한다.
(자바 바이트 코드를 어떻게 실행해야될지에 대한 표준 스펙이며 구현체라 볼 수 있다.)
JVM 때문에 JAVA 가 플랫폼 독립적이라고 흔히들 말하는데
JVM 자체는 OS(플랫폼)에 종속적이다.플랫폼에 종속적인 이유
자바 바이트 코드를 네이티브 코드(OS에 특화된)로 바꾸어서 실행해야 하기 때문
소스코드를 작성하는 JAVA 언어는 JVM 덕분에 플랫폼 독립적이다.JVM 의 구현체는 다양하다
Oracle, Amazon, Azul 등 다양한 벤더들이 있다.
자바 바이트코드?
.java
파일을 javac(자바컴파일러)를 통하여.class
파일 (자바바이트코드)로 만들 수 있다.
JVM은 바이트코드(.class) 를 네이티브 코드로 변환한다.다른 언어로 작성된 파일들은 JVM 에서 돌릴 수 없다?
다른언어로 작성되었더라도, 바이트코드로만 변환할 수 있다면 JVM 에서 실행할 수 있다.
JVM에 오래 쌓여진 노하우(안정성), 성능 최적화, 프로파일링 툴등을 그대로 활용할 수 있다.
2. JRE (Java Runtime Environment) = JVM + @
JRE 의 목적
JAVA 어플리케이션을 실행하는 것
실행하는데 필요한 것만 들어있음
개발관련 도구(javac 등)는 제공하지 않음
3. JDK (Java Development Kit)
JRE(JVM+라이브러리) + 개발관련 도구(javac, javadoc 등)
오라클은 JAVA 11 부터 JDK만 제공하며, JRE는 따로 제공하지 않는다.Oracle JDK 11 버전부터 유료?
벤더가 다르거나, OpenJDK이면 무료다.
# JVM 의 구조 및 개요
1. 클래스 로더 시스템
- 로딩 : .class 를 읽어옴
- 링크 : 레퍼런스를 연결
2. 메모리
- 공유자원
- 메소드(method) 영역에는 클래스 수준의 정보 (클래스 이름, 부모클래스 이름, 메소드, 변수) 를 저장
- 힙(heap) 영역에는 객체를 저장
- 쓰레드 영역
- `스택(stack), PC Register, 네이티브 메소드 스택` 은 쓰레드마다 가진다.
- PC(Program Counter) 는 쓰레드 내 현재 실행할 스택 프레임을 가리키는 포인터를 담고있다.
- 네이티브 메소드 스택(Native Method Stack) 은 네이티브 메소드(native 키워드) 를 호출 할 때 사용하는 별도의 스택
3. 네이티브 메소드 라이브러리
- C/C++ 로 작성된 라이브러리
4. 실행엔진
- 인터프리터 : 바이트 코드를 한줄 씩 실행
- JIT 컴파일러 : 반복되는 코드를 모두 네이티브 코드로 바꿔두어 인터프리터 실행속도를 높인다.
- Garbage Collector : 더 이상 참조되지 않는 객체의 메모리를 수거한다.
- GC 의 종류는 많고, 개발자가 선택해서 사용할 수도 있다.
# 클래스로더 시스템
1. 로딩
- 동작
- 클래스 로더가 .class 파일(바이트코드)을 읽어 바이너리 데이터로 클래스정보와 함께 Method 영역에 저장
- 로딩이 끝나면 해당 클래스타입의 Class 타입의 인스턴스를 생성하여 메모리 영역에 저장
- 보통 Method 영역이지만, Heap 영역에 저장될 수 도 있다.
- getClass() 메소드를 호출하면 Heap 영역에 저장된 객체를 가져온다.
- Class<클래스명> 이 Heap 에 저장된 클래스 객체
- 보통 Method 영역이지만, Heap 영역에 저장될 수 도 있다.
- 최상위 클래스로더가 먼저 로딩작업을 수행하고, 못읽으면 자식 클래스로더에게 패스하는 식으로 클래스를 로드함
- 최하위 클래스로더가 못 읽으면 ClassNotFoundException() 이 발생
- 최하위 클래스로더가 못 읽으면 ClassNotFoundException() 이 발생
- 이전 클래스로더가 읽은 클래스는 다음 클래스로더가 읽지 않는다.
- 클래스 정보에 포함된 것들
- FQCN(Full Qualified Class Name)
- 패키지경로, 패키지이름, 클래스이름, 클래스로더
- 4개 중 1개라도 다르면 JVM 안에서 다른 클래스 취급을 한다.
- 메소드와 변수
- 클래스 타입
- Class, Interface, Enum
- FQCN(Full Qualified Class Name)
- 클래스 로더의 종류
- BootStrap ClassLoader
- getClassLoader() 로 확인할 수 없는 네이티브 코드로 구현 된 최상위 클래스로더
- BootStrap ClassLoader 는 JVM이 초기화되면서 필요한 클래스들을 읽는다.
- System.getProperty("sun.boot.class.path")에서 확인할 수 있다.
- System.getProperty("sun.boot.class.path")에서 확인할 수 있다.
- Extension(Platform) ClassLoader
- BootStrap ClassLoader 가 못 읽은 부분을 읽어들임
- BootStrap ClassLoader 가 못 읽은 부분을 읽어들임
- Application ClassLoader
- Platform ClassLoader 가 못 읽은 부분을 읽어들임
- JVM 초기화 과정이 끝나면 Application ClassLoader 가 어플리케이션 클래스들을 로딩한다.
- System.getProperty("java.class.path")에서 값을 확인할 수 있다.
- BootStrap ClassLoader
- 해당 객체를 읽어들인 클래스로더의 종류 알아보는법
클래스명.class.getClassLoader();
2. 링크
- Verify
- .class 파일(바이트코드)의 형식이 유효한지 체크
- Preparation
- 클래스 변수(static 변수)와 기본값에 필요한 메모리를 준비
- Resolve
- 심볼릭 메모리 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 교체한다
- 링크 단계에서 Resolve 가 발생할 수 도 있고, 레퍼런스가 실제로 참조될 때 발생할 수 도 있다.
3. 초기화
- static 변수의 값을 할당
# ClassPath
JVM(java.exe)이 수행할 클래스의 위치가 classpath이다.
SpringBoot 가 아닌 Spring Framework 를 사용하면 흔히 만나는 친구이다.
리소스 관련 라이브러리를 사용할 떄도 종종 등장한다.
ClassLoader 가 읽어들일 ClassPath 를 직접 설정해줄 수 도 있다.
( #Reference. Java ClassLoader 이해하기 참조)
# Reference
728x90'프로그래밍 언어 > Java' 카테고리의 다른 글
[Java/Kotlin] Static nested class 와 Inner Class 중 무엇을 써야할까? (0) 2022.11.06 [Java] 바이트코드 조작하기 (JavaAgent, JVM, Jacoco) (0) 2022.06.06 [Java/OS] 세마포어(Semaphore)에 관하여 (2) 2022.03.18 [Java] ThreadLocal 이 필요할 때 (feat. Thread, Thread-Safe, OS, Spring Security) (0) 2022.03.15 [Java 성능개선] for 루프와 String 연산, 입출력 (0) 2022.01.26