https://howtodoinjava.com/java/basics/jdk-jre-jvm/
사이트와 책 'JVM Performance Optimizing 및 성능 분석 사례'를 함께 보았다.
1. 왜 Java Virtual Machine 일까?
2. 자바 프로그래밍의 실행(Execution of a Java Program) With JVM
개략적으로 살펴보면,
작성한 .java 파일을 .class 파일로 컴파일 하여 얻은 바이트 코드가 JVM 에서 실행된다. 그래서 바이트 코드로 올라온 것부터 JVM의 영역이라고 할 수 있을 것 같다. 헷갈리지 말아야 할 점은 JVM은 바이트 코드가 런타임 환경에서 실행될수 있는 정보를 제공하는 명세일뿐이다. 다양한 벤더들은 이 명세의 구현 방법들을 제공하고 있는데 아래의 사이트에서 그 리스트 자세한 내용을 다룬다.
https://en.wikipedia.org/wiki/List_of_Java_virtual_machines
가장 대중적인 JVM 구현은 Hotspot 으로 Oracle 에서 소유하며 제공되고 있다.
JVM 은 다양한 기술(incorporating a state-of-the-art memory model, garbage collector, and adaptive optimizer) 을 이용해서 자바 애플리케이션들을 위한 최적의 퍼포먼스들을 제공한다.
JVM 과 실행되는 자바의 구현 과정을 그림으로 자세히 살펴보면,
1. 에디터나 IDE(Intergrated development enviroment) 를 이용해서 Simple.java 코드를 작성한다.
2. 프로그램은 바이트 코드로 컴파일 되어야 하며 Java Compiler(javac) 는 소스코드를 Simple.class 로 컴파일 한다.
3. 컴파일된 클래스 파일은 어떠한 플랫폼이나 OS에서 JVM (Java virtual machine) 에 의해 실행 될 수 있다.
4. JVM은 바이트 코드를 기계가 실행할 수 있는 네이티브 시스템 코드로 변환한다.
컴파일 과정을 통하여 생성된 Class 파일을 JVM 으로 로딩하고 ByteCode 를 해석(interpret)하는 과정을 거쳐 메모리 등의 리소스를 할당하고 관리하며 정보를 처리하는 일련의 작업들을 포괄한다. 이때 JVM은 Thread 관리 및 Garbage Collection 과 같은 메모리 정리 작업도 수행하게 된다.
이번엔 JVM 의 내부 구조를 확대한다.
[그림] 은 기본적인 Java 프로그램의 수행과정을 도식화 한 그림으로 JVM 상에서 Class Loader 를 통해 Class 파일들을 로딩시키고, 로딩된 Class 파일들은 Execution Engine 통해 해석된다. 해석된 프로그램은 Runtime Data Areas 에 배치되어 실질적인 수행이 이루어지게 된다.
- Java Source : 사용자가 작성한 Java 코드이다. (확장자 .java)
- Java Compiler : Java Source 파일을 JVM 이 해석할 수 있는 Java Byte Code 로 변경한다.
- Java Byte Code : Java Copiler 에 의해 수행될 결과물이다. (확장자 .class 파일)
- Execution Engine : Loding 된 클래스의 Bytecode를 해석(Interpret) 한다.
- Runtime Data Area : JVM 이라는 프로세스가 프로그램을 수행하기 위해 OS 에서 할당받은 메모리 공간이다.
Runtime Data Areas
- Method Area : 클래스, 변수, Method, static 변수, 상수 정보 등이 저장되는 영역이다. (모든 Thread 가 공유한다.)
- Heap Area : new 명령어로 생성된 인스턴스와 객체가 저장되는 구역이다. (Garbage Collection 이슈는 이 영역에서 일어나며, 모든 Thread 가 공유한다.
- Stack Area : Method 내에서 사용되는 값들(매개변수, 지역변수, 리턴값 등)이 저장되는 구역으로 메소드가 호출될 때 LIFO 로 하나씩 생성되고 메소드 실행이 완료되면 LIFO 로 하나씩 지워진다. (각 Thread 별로 하나씩 생성된다.
- PC Register : CPU 의 Register 와 역할이 비슷하다. 현재 수행 중인 JVM 명령의 주소값이 저장된다. (각 Thread 별로 하나씩 생성된다.
- Native Method Stack : 다른 언어(C/C++ 등)의 메소드 호출을 위해 할당되는 구역으로 언어에 맞게 Stack 이 형성되는 구역이다.
이러한 실행 과정 속에서 JVM 은 필요에 따라 Thread Synchroniztion 과 Garbage Collection 과 같은 관리 작업을 수행하게 된다.
3. JVM Architecture
위 그림에서 보았던 Runtime Data Area 영역의 JVM Memory 부분이다.
3.1 Java Heap
- Thread 공유의 정보는 Stack에 저장이 되고 Class 나 Method 정보, Bytecode 등은 Method Area 에 저장된다. 이 Java Heap 은 단순히 Instacne(Object) 와 Array 객체 두가지 종류만 저장되는 공간에 지나지 않는다.
- 모든 Thread 들에 의해 공유되는 영역이며 같은 애플리케이션을 사용하는 Thread 사이에서는 공유된다
- JVM 은 Java Heap 에 Memory를 할당하는 Instruction(Bytecode로 new, newarray, anewarray, multinewarry) 만 존재하고 메모리 해제를 위한 어떤 Java Code 나 Bytecode 도 존재하지 않는다. Java Heap의 메모리 해제는 오로지 Garbage Collection을 통해서만 수행된다.
3.1 Hotspot JVM 의 Heap 구조
- Young Generation : Eden 영역과 Survior 의 영역
- Eden : Object 가 Heap 에 최초로 할당되는 장소, 영역이 꽉 차게 되면 Live Object 일 경우 Survior 로 넘기고, 참조가 끊어진 Garbage Object 이면 그냥 남겨 놓는다. 모든 Live Object가 Survior 영역으로 넘어가면 Eden 영역을 모두 청소(Scanvenge) 한다.
- Survior : Eden 영역에서 살아남은 Object 들이 잠시 머무르는 곳
- Minor GC : Survior 영역에서 이루어 지는 GC
- Old Generation : Young Generation 에서 Live Object 로 오래 살아남아 성숙된 Object 를 이동시키는 영역
- Major GC : Young -> Old Generation 영역으로 Promotion 과정중 Old Generation 의 메모리도 충분하지 않으면 해당 영역에서 발생하는 GC
- Perm : 보통 Class 의 Meta 정보, Method 의 Meta 정보, Static 변수와 상수 정보들이 저장되는 공간으로 흔히 메타 데이터 저장 영역이라고도 한다. 이 영역은 Java 8 부터는 Native 영역으로 이동하여 Metaspace 영역으로 변경 되었다. (다만, 기존 Perm 영역에 존재하던 Static Object 는 Heap 영역으로 옮겨져서 GC 의 대상이 최대한 될 수 있도록 하였다.)
Java8 에서의 JVM 메모리 구조 개선 사항
최근 자바 8 에서 JVM 메모리 구조적인 개선 사항으로 Pem 영역이 Metaspace 영역으로 전환되고 기존 Perm 영역은 사라지게 되었다.
Metaspace 영역은 Heap 이 아닌 Native 메모리 영역으로 취급하게 된다.
(Heap 영역은 JVM 에 의해 관리된 영역이며 Native 메모리는 OS 레벨에서 관리 하는 영역으로 구분된다.)
Metaspace 가 Native 메모리를 이용함으로서 개발자는 영역 확보의 상한을 크게 의식할 필요가 없어지게 되었다.
JDK 7 이하는 옵션 방식이 다르기 때문에 따로 확인해 보아야 한다.
Heap 의 메모리 저장 정보는 아래와 같이 차이가 난다.
구분 | 상세구분 | ~ Java 7 까지의 버전(Perm) | ~ Java 8 까지의 버전(Metasapce) |
저장 정보 | Class 의 Meta 정보 | 저장 | 저장 |
Method 의 Meta 정보 | 저장 | 저장 | |
Static Object 변수, 상수 | 저장 | Heap 영역으로 이동 | |
관리 포인트 | 메모리 관리(튜닝) | Heap 영역 튜닝외에 Peram 영역 별도 튜닝 필요 |
Heap 영역 튜닝 Native 영역 동적 조정 (별도 옵션으로 조절 가능) |
메모리 측면 | 메모리 크기(옵션) | -XX:PermSize -XX:MaxPermSize |
-XX:MetaspaceSize -XX:MaxMetaspaceSize |
아래 사이트에서 Metasize 조회 방법, JDK 7, JDK 8 으로 Heap 설정이 달라진 부분이 잘 나와있다. (그 안에 링크까지)
4. Garbage Collection
4.1 Garbage?
Garbage : 사용되지 않은 Object 를 의미한다. 그리고 그 오브젝트를 모아 처리하는 것이 가비지 컬렉션이다.
4.2 Object 의 사용 여부 판단 방법
- Root Set 과의 관계로 판단한다. (Reachable or Not Reachable)
Root Set 은 아래와 같이 3가지 참조형태를 통해 Reachable Object 를 판단한다.
- Local variable Section, Operand Stack 에 Object 의 Reference 정보가 있다면 Reachable Object!
- Method Area에 로딩된 클래스 중 constance pool 에 있는 Reference 정보를 토대로 Thread에서 직접 참조 하지 않지만 Constance pool을 통해 간접 link 를 하고 있는 Object는 Reachable Object!
- 아직 Memory에 남아 있으며 Native Method Area로 넘겨진 Object 의 Reference 가 JNI 형태로 참조 관계가 되어있는 Object 는 Reachable Object 이다.
4.3 Memiry Leak 가 발생했다는 것 With GC
public class Main {
public static void main(String[] args) {
Leak lk = new Leak();
for(int a =0; a < 90000000; a++) {
lk.addList(a);
lk.removeStr(a);
}
}
}
public class Leak {
ArrayList list = new ArrayList();
public void addList(int a) {
list.add("add :" + a);
}
public void removeStr(int i) {
Object obj = list.get(i);
obj = null;
}
}
'java' 카테고리의 다른 글
[JAVA]java Serializable (0) | 2021.11.04 |
---|---|
[JAVA] 자바의 정석 - Stream (0) | 2021.10.31 |
[JAVA] 자바의 정석 - Execption 정리 (0) | 2021.10.21 |
[JAVA] Concurrent Collections - ConcurrentHashMap() (0) | 2021.10.11 |
[JAVA] Map 정리(HashMap , TreeMap , Red-Black Tree ) (0) | 2021.10.11 |