티스토리 뷰
JVM 구조
클래스 로더 시스템, 메모리, 실행 엔진, 네이티브 메서드 인터페이스, 네이티브 메소드 라이브러리가 존재한다.
이미지는 다음 링크를 참고하자.
자바 가상 머신 - 위키백과, 우리 모두의 백과사전
ko.wikipedia.org
1. 클래스 로더 시스템
1.1 로딩(loading)
클래스 로더가 프로젝트 내에 있는 소스 코드 형태로 되어 있는 .class 파일을 읽는다.
그 파일의 내용을 binary 데이터를 만들고, 메소드에 저장한다.
이 때 저장하는 데이터는 다음과 같다.
- FQCN(Fully Qualified Class Name)
- 그 파일이 클래스인지 인터페이스인지 enum인지에 대한 식별 정보
- 파일 내에 있는 메서드와 프로퍼티 정보
로딩이 끝나면 해당 클래스 타입의 Class 객체를 생성하여 힙에 저장한다.
다음과 같은 Person 클래스가 있다고 해보자.
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
이 클래스의 로딩이 끝나면 다음과 같이 Class 객체가 생성되어 사용할 수 있게 된다.
public class Main {
public static void main(String[] args) {
// [1]
System.out.println(Person.class);
// [2]
Person person = new Person("eric", 27);
System.out.println(person.getClass());
// [3]
Class<Person> personClass;
}
}
// 결과
class com.example.kkoon9.kwon.Person
class com.example.kkoon9.kwon.Person
힙과 메서드 영역에 있는 데이터들은 쓰레드에 국한되지 않고, 공용으로 사용될 수 있다.
클래스 로더에는 다음과 같이 세 가지 종류가 존재한다.
- 부트 스트랩
- 플랫폼(前 Extension)
- 애플리케이션
위는 다음 코드를 통해서 확인해볼 수 있다.
public class Main {
public static void main(String[] args) {
ClassLoader classLoader = Person.class.getClassLoader();
System.out.println(classLoader);
System.out.println(classLoader.getParent());
System.out.println(classLoader.getParent().getParent());
}
}
// 실행결과
jdk.internal.loader.ClassLoaders$AppClassLoader@277050dc
jdk.internal.loader.ClassLoaders$PlatformClassLoader@cac736f
null
아까 만든 Person 클래스에서 getClassLoader() 메서드를 통해 클래스 로더를 가져올 수 있다.
클래스 로더는 트리 구조를 가지기 때문에 getParent() 메서드를 통해 부모를 가져올 수 있다.
실행 결과를 보면 AppClassLoader, PlatformClassLoader, null이 뜨게 된다.
AppClassLoader는 Application 클래스 로더를 뜻한다.
🤔
마지막 null은 무엇일까?
부트스트랩 클래스 로더는 네이티브로 구현되어 있기 때문에 코드에서는 참조할 수 없다고 한다.
우리가 작성하는 코드는 대부분 AppClassLoader에서 읽게 된다.
🤔
세 가지 클래스 로더에서 우선순위도 존재할까?
물론 존재한다.
제일 부모인 부트스트랩 클래스 로더부터 읽어오고, 만약 읽지 못했다면 그 다음 클래스 로더에서 읽게 된다.
1.2 링크(link)
링크는 다음과 같은 세 단계로 나뉠 수 있다.
- Verify : .class 파일 형식이 유효한지 체크하는 과정이다.
- Prepare : 클래스 변수와 기본값에 필요한 메모리를 준비하는 과정이다.
- Resolve(Optional) : 심볼릭 메서드 레퍼런스를 실제 레퍼런스로 교체하는 과정이다.
1.3 초기화(initialization)
static한 변수들이 이 단계에서 할당이 된다.
2. 메모리
2.1 메서드(method)
클래스 수준의 정보가 저장되며, 위에서 언급한대로 데이터가 다른 쓰레드에도 공유된다.
클래스 수준의 정보는 다음과 같다.
- 클래스 이름
- full package path
- 부모 클래스 이름
- 메서드
- 변수
2.2 힙(heap)
객체를 저장되며, 위에서 언급한대로 데이터가 다른 쓰레드에도 공유된다.
클래스의 인스턴스 역시 이 영역에 저장된다.
2.3 스택(stack)
런타임 스택을 만들고 그 안에 메서드 호출을 콜 스택에 블럭으로 쌓는다.
쓰레드가 종료하면 런타임 스택도 사라진다.
콜 스택은 애플리케이션 내 에러가 발생하면 터미널에 나타나는 로그들을 예시로 들 수 있다.
다른 쓰레드에 공유되지 않고, 그 쓰레드에 국한된다.
2.4 PC 레지스터(Promgram Counter register)
쓰래드 내 다음 명령의 위치를 가리키는 포인터를 의미한다.
다른 쓰레드에 공유되지 않고, 그 쓰레드에 국한된다.
2.5 네이티브 메서드 스택(native method stack)
이름 그대로 네이티브 메서드를 호출할 때 쌓이는 스택을 의미한다.
다른 쓰레드에 공유되지 않고, 그 쓰레드에 국한된다.
3. 네이티브 메서드 인터페이스(JNI), 네이티브 메서드 라이브러리
네이티브 메서드 라이브러리는 native 키워드가 붙어 있으며, C, C++로 작성된 라이브러리를 의미한다.
예시로, Thread의 currentThread() 메서드가 있다.
JNI는 Java Native Interface의 약자로, 자바 애플리케이션에서 위같은 메서드를 사용할 수 있도록 도와준다.
4. 실행 엔진
바이트 코드를 실행시키는 역할을 수행한다.
인터프리터, JIT 컴파일러, GC로 이루어져 있는데, 다른 포스팅에서 자세히 다룰 예정이다.
Java의 실행방식
- 자바 컴파일러가 자바 소스코드(.java)를 읽어 자바 바이트코드(.class)로 변환시킨다.
- 클래스 로더를 통해 클래스 파일들을 JVM으로 로딩한다.
- 로딩된 클래스 파일들은 실행 엔진을 통해 해석된다.
'JAVA' 카테고리의 다른 글
| new String()과 ""의 차이점과 불변 클래스 (0) | 2023.02.09 |
|---|---|
| 오브젝트의 동일성과 동등성 (0) | 2022.07.10 |
| 방어적 복사 (0) | 2022.05.01 |
| java에서 멀티쓰레드 [3] Callable과 Future (0) | 2022.02.07 |
| java에서 멀티쓰레드 [2] Executors와 ExecutorService (0) | 2022.02.07 |
- Total
- Today
- Yesterday
- 프로그래머스
- BOJ
- 코테
- 이펙티브 자바
- Spring Boot
- MSA
- C++
- 디자인 패턴
- Effective Java
- 알고리즘
- Java
- programmers
- 정규표현식
- 객체지향
- Algorithm
- Spring
- Olympiad
- 클린 코드
- 이팩티브 자바
- node.js
- 테라폼
- kkoon9
- 클린 아키텍처
- kotest
- BAEKJOON
- 디자인패턴
- Kotlin
- 백준
- JPA
- AWS
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |