참고
howtodoinjava.com/java/basics/jdk-jre-jvm/
www.inflearn.com/course/the-java-code-manipulation/dashboard
0. 프로세스 설명
- Simple.Java 라는 자바 소스코드를 IDE (eclipse / intellij) 를 통해 작성한다.
- 해당 파일을 자바 컴파일러가 (javac) 컴파일하여 바이트코드로 만든다. (Simple.class)
- 해당 클래스 파일은 JVM 에 의해 실행된다.
- JVM은 바이트코드를 native Code(JVM이 실행할 수 있는 코드) 로 바꿔서 실행한다.
간단한 과정을 수행해보자.
예시) HelloJava.java를 컴파일하고 실행해보자.
1. HelloJava.java
public class HelloJava {
public static void main(String[] args) {
System.out.println(".java 파일입니다.");
}
}
2. javac 로 컴파일
javac HelloJava.java
3. HelloJava.class 확인
- javap -c 를 사용하면 바이트코드를 잘 포맷된 모습으로 볼 수 있다. (실제로 열어서보면 아래와 같이 생기지 않았음)
javap -c HelloJava.class
결과
Compiled from "HelloJava.java"
public class HelloJava {
public HelloJava();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #13 // String .java 파일입니다.
5: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
4. 실행
- java HelloJava
1. JVM
- 정의
- Java 바이트코드(.class) 파일을 native 코드로 변환하여
- 실행하는 것에 대한 표준이다.
- native 코드로 변환하는 과정은
- JIT (Just In Time) Compiler 혹은
- Interceptor 가 제공한다.
아.. JVM은 native 코드를 실행해주는구나
- 그렇다면 가장 먼저 뭘 해야할까? -> class file을 로딩해야지
1.1 Class Loader
- class file을 로딩하는데 사용되는 시스템이 JVM 내부에 있는 Class Loader 이다.
3가지의 기능을 제공한다.
- Loading
- .class 파일(바이트 코드) 을 읽어 "메소드" 영역에 저장한다.
- JVM에는 3종류의 Loader가 있다. (BootStrap, extension and application class loader)
- 처음으로 BootStrap class loader 은 .class 파일을 찾으려고 한다. JRE의 lib 폴더안에 rt.jar 파일을 스캔한다.
- rt.jar 파일은 모든 JRE의 라이브러리를 갖고있다.
- BootStrap이 찾지 못했다면 extension은 jre/lib/ext 폴더에서 class파일을 찾는다.
- extension도 찾지 못했다면, application classloader가 CLASSPATH environment로 주어진 곳에서 클래스파일을 찾는다.
- 여기서도 찾지 못했다면 ClassNotFoundException 이 던져진다.
- 처음으로 BootStrap class loader 은 .class 파일을 찾으려고 한다. JRE의 lib 폴더안에 rt.jar 파일을 스캔한다.
- Linking
- classLoader에 의해서 로딩이 됐다면, bytecode verifier 가 바이트코드에 대한 검증을 한다.
- 문제없는 바이트코드라면, 클래스 파일에서 찾은
- static 변수
- static method를 메모리할당을 준비한다.
- Initializing
- 모든 static 변수들에 값이 할당되고, static block 이 수행된다.
- // static 값들은 아래에 설명하게 될 Method Area에 저장된다.
- 모든 static 변수들에 값이 할당되고, static block 이 수행된다.
로딩이 끝나면, 해당 클래스 타입의 객체 (Class<?>, ?.class)를 "Heap" 영역에 저장한다.
- 따라서 우리는 ???.class 를 사용할 수 있는것이다.
메모리에 올린다라.. 근데 어디에 올리지?
1.2 JVM Memory Areas
- JVM 내부에 메모리 영역은 여러 바트로 나뉘어있다.
영역 | 역할 |
Method Area | 클래스 수준에 대한 정보가 저장된다. - 패키지 정보가 포함된 클래스 이름 (ex) com.tistory.robin00q.MyClass - 부모 클래스의 이름 (아무것도 상속받지 않은 클래스도 Object 클래스는 상속받는다.) - 클래스 안에 있는 메소드 - 클래스 안에 있는 변수들 - 클래스 타입 (클래스인지, 인터페이스인지, Enum인지) 위에 명시한 클래스 수준에 대한 정보들은 Thread가 공유하는 자원이다. Runtime Constant Pool - 클래스 수준 정보에 대한 모든 레퍼런스(주소)를 저장한다. - JVM은 런타임에 Constant Pool을 통해서 실제 메모리 주소를 찾아서 참조한다. |
Heap | 객체를 저장하는 영역이다. - 위의 Method Area 에서 클래스에 대한 정보를 저장했다면, 실제 인스턴스들을 저장한다. 객체에 대한 정보 또한 Thread가 공유하는 자원이다. |
Stack | Thread 별로 독립적이다. // Stack에 대한 설명은 너무 길어질 수 있기에 인터넷에서 찾아보시는게 TT |
PC register | Thread 별로 독립적이다. - 만들어진 stack에 현재 어느 부분의 스택 프레임을 실행할 것인지를 가리키는 포인터이다. - 해당 정보를 참조해 어떤 명령어를 수행할지 알 수 있다. |
Native Method Stacks | 자바는 많은 low level code 가 c, c++ 로 작성되었기 때문에, 해당 코드를 사용하기 위한 Stack이다. |
다 할당했으면 이제 실행을 해보자
1.3 JVM Execution Engine
- JVM에 할당된 코드들은 모두 execution engine 에 의해서 실행된다.
- byte code를 machine code로 변경하고 실행한다.
- 두가지 종류의 execution engine이 존재하며 아래와 같다.
- Interpreter
- 바이트코드를 하나씩 읽어서 실행하며, 최적화를 적용하지 않는다.
- 한줄, 한줄 읽어서 machine code로 바꿔서 실행한다.
- 바이트코드를 하나씩 읽어서 실행하며, 최적화를 적용하지 않는다.
- JIT Compiler
- 실행 시점에서는 인터프리터 역할을 하며, 바이트코드를 machine 코드로 변경한다.
- 실행 과정에서 코드를 캐싱하여, 추후에 다시 코드가 불리는 경우 재사용하여, 매번 machine 코드를 생성하는 것을 방지한다.
- 실행 시점에서는 인터프리터 역할을 하며, 바이트코드를 machine 코드로 변경한다.
- Interpreter
자바 바이트코드 ??
- JVM 이 이해할 수 있는 언어로 변환된 Java 코드 (.class) 이다.
2. JRE
- JRE(Java Runtime Environment)
- 자바 어플리케이션을 실행하는데 목적이 있다.
- 실행하기 위해서는 바이트 코드가 일단 필요하기에 JVM
- 자바의 핵심 library를 사용하기 위한 Library들 (jars)
- 자바 어플리케이션을 실행하기 위해 필요한 최소한의 Library들이다.
- 자바 어플리케이션을 실행하는데 목적이 있다.
3. JDK
- JRE + 개발에 필요한 툴을 제공한다.
- developing
- debugging
- monitoring 등..
'WhiteShip Study' 카테고리의 다른 글
2. 자바 데이터 타입, 변수 그리고 배열 (0) | 2020.12.11 |
---|