-
[Java Study] - JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.Java 2021. 9. 16. 19:52
JVM이란 무엇인가
JVM (Java Virtual Machine) : 자바 프로그램이 실행되는 가상 컴퓨터(VM)
운영체제에서 바로 실행하면 되는 데 JVM 이라고 하는 가상 머신(기계)이 왜 필요 한 것인가 ??
- 자바 프로그램은 바이트 코드 이기 때문에 운영체제가 이것을 해석하고 실행 할 수 없다.
- 자바 가상 머신으로 자바 바이트 코드(.class 파일)를 OS에 특화된 코드로 변환(인터프리터와 JIT 컴파일러)하여 실행한다.
- JVM이 자바를 실행하는 가상의 운영체제 역할을 담당 한다.
- 즉 , JVM은 운영체제와 자바 프로그램를 연결 해주는 중간 다리라고 보면 된다.
- 그렇기 때문에 운영체제에 맞는 JVM을 설치하기만 하면 모든 운영체제에서 자바를 실행 할 수 있다.
자바는 운영체제에 독립적, JVM은 운영체제에 종속적이다.
컴파일 하는 방법
자바 프로그램에서 컴파일이란?
- JVM은 java code를 이해하지 못한다.
- java code(텍스트 파일)을 JVM이 사용할 수 있게 class file(.class)를 생성하는 것을 말한다.
1.자바 설치(JDK)
- JDK 폴더 안에는 javac.exe 라는 자바 컴파일러가 포함 되어 있다.
※ 자바 컴파일러(Java compiler)
자바를 가지고 작성한 자바 소스 코드를 자바 가상 머신이 이해할 수 있는 자바 바이트 코드로 변환해준다.
자바 컴파일러는 자바를 설치하면 javac.exe 라는 실행 파일 형태로 설치된다.
2. java 소스 파일 작성하기
public class Hello { public static void main(String\[\] args) { System.out.println("hello world"); } }
3. 자바 컴파일러 실행
- Hello.java 컴파일
- 명령 프롬프트 실행 -> 소스 파일이 있는 경로로 이동(cd 파일경로)
- javac.exe (.exe 생략 가능) -> javac Hello.java 입력
- 바이트 코드 Hello.class 가 생성됨
실행하는 방법
JDK 폴더 안에 자바를 실행할 수 있는 java.exe가 있다.
- 명령 프롬프트 실행 -> 컴파일된 파일 경로로 이동
- java.exe로 자바 실행
- java Hello 입력 (바이트 코드 파일을 실행할 때 .class 확장명을 제외하고 입력해야 함)
- JVM이 바이트 코드 파일을 메모리에 로드하고 , 기계어로 번역한다.
- java main() 메소드를 찾아 실행한다.
바이트코드란 무엇인가
JVM(자바 가상 머신) 이 이해할 수 있는 언어로 변환된 코드를 의미
- Java Code(소스 파일)를 컴파일 한 결과로 생성된 코드이다.
- JVM이 이해할 수 있는 언어이다.
- Java Code 와 Machine Code 의 중간 코드이다.
- 자바 컴파일러에 의해 변환되는 코드의 명령어 크기가 1바이트라서 자바 바이트 코드라고 불린다.
- 확장자는 .class이다.
- JVM만 설치되어 있으면, 어떤 운영체제에서라도 실행될 수 있다.
javap
javap 는 .class 파일의 필드, 생성자, 메서드들의 정보를 보여주는 명령어이다.
Hello.java
public class Hello { public static void main(String[] args) { System.out.println("hello , java"); } }
javap : 최소 구성만 보여준다.
javap Hello.class
Compiled from "Hello.java" public class step1.Hello { public step1.Hello(); public static void main(java.lang.String[]); }
javap -p : 모든 클래스와 멤버를 보여준다.
javap -p Hello.class
Compiled from "Hello.java" public class step1.Hello { public step1.Hello(); public static void main(java.lang.String[]); }
javap -v : stack size , arguments for methods 와 같은 자세한 정보를 보여준다.
javap -v Hello.class
Last modified 2021. 10. 12.; size 422 bytes MD5 checksum ff4146e1163a7cb1070c19e462ccf9f6 Compiled from "Hello.java" public class step1.Hello minor version: 0 major version: 55 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #5 // step1/Hello super_class: #6 // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 1 Constant pool: #1 = Methodref #6.#15 // java/lang/Object."<init>":()V #2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #18 // hello , java #4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #21 // step1/Hello #6 = Class #22 // java/lang/Object #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 main #12 = Utf8 ([Ljava/lang/String;)V #13 = Utf8 SourceFile #14 = Utf8 Hello.java #15 = NameAndType #7:#8 // "<init>":()V #16 = Class #23 // java/lang/System #17 = NameAndType #24:#25 // out:Ljava/io/PrintStream; #18 = Utf8 hello , java #19 = Class #26 // java/io/PrintStream #20 = NameAndType #27:#28 // println:(Ljava/lang/String;)V #21 = Utf8 step1/Hello #22 = Utf8 java/lang/Object #23 = Utf8 java/lang/System #24 = Utf8 out #25 = Utf8 Ljava/io/PrintStream; #26 = Utf8 java/io/PrintStream #27 = Utf8 println #28 = Utf8 (Ljava/lang/String;)V { public step1.Hello(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String hello , java 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 5: 0 line 6: 8 }
javap -c : .class 파일을 분해해서 해석해준다.
javap -c Hello.class
Compiled from "Hello.java" public class step1.Hello { public step1.Hello(); 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 #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String hello , java 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return }
JIT 컴파일러란 무엇이며 어떻게 동작하는지
bytecode를 기계어로 변환하기 위해 JVM Execution Engine(실행 엔진)에 있는 Interpreter 와 JIT 컴파일러가 구동된다.
Interpreter가 매번 바이트 코드를 읽고 한 줄 씩 기계어 코드를 생성하고 이를 순차적으로 실행한다.
심지어 같은 메서드를 여러번 호출 할 때, 매번 한 줄씩 interpreter 가 구동된다.이로 인해 시스템 효율과 성능이 떨어질 수 있다.
JIT(Just-In-Time) 컴파일러가 이 점을 보완 해 줄 수 있다.
인터프리터 방식으로 기계어를 생성할 때 자주 사용되는 메서드, 변수 그리고 여러번 호출 되는 메서드를 캐싱하여
재사용 할 수 있다. 이는 매번 기계어 코드를 생성하는 것을 방지 할 수 있다.요약하면
- JIT 컴파일러는 자바 컴파일러(javac.exe)와 다른 별개의 컴파일러이다.
- interpreter 방식 과 정적 compile 방식을 혼합한 방식이다.
- JVM의 구성 요소 중 하나이다.
- 바이트 코드를 기계어로 컴파일 할 때 사용
- 실행 과정에서 컴파일 하는 방식이다. (동적 컴파일 방식)
JVM 구성 요소
바이트 코드를 읽고 자바를 실행 하는 JVM의 구성 요소를 살펴보자
- Class Loader
- 컴파일 된 .class file을 읽은 뒤 Method Area에 저장한다.
- 로딩 : 클래스를 읽어 오는 과정
- 링크 : 레퍼런스를 연결하는 과정
- 초기화 : static 값들 초기화 및 변수에 할당
- Runtime Data Area : JVM이 Java Bytecode를 실행하기 위해 사용하는 메모리 공간
- method area : 클래스 로더가 클래스 파일을 읽어오면 클래스 정보(runtime constant pool , field , method data , code for methods)
를 파싱해서 저장하는 곳 - heap : 프로그램을 실행하면 생성한 모든 객체를 저장하는 곳
- pc registers : 각 스레드가 메서드를 실행하고 있을 때, 메서드 안에 몇 번째 줄을 실행해야 하는지 나타내는 역할
- stack : 스레드 별로 1개만 존재한다. 스택 프레임은 메서드가 호출될 때 마다 생성된다. 메서드 실행이 끝나면 스택 프레임은 pop되어 제거된다.
- method area : 클래스 로더가 클래스 파일을 읽어오면 클래스 정보(runtime constant pool , field , method data , code for methods)
- native method stacks : Java Bytecode가 아닌 다른 언어로 작성된 메서드를 의미
- Execution Engine : 바이트코드를 실행 하는 곳
- Interpreter : 바이트코드를 한 줄 씩 읽어서 기계어로 변환한다. 한 줄 씩 읽어서 변환 하기 때문에 느릴 수 있다.
- JIT Compiler : 위에서 언급한 interpreter의 단점을 보완해 줄 수 있다.
코드 중에 반복되거나 자주 실행되는 코드를 기계어로 컴파일 한 뒤 캐싱해서 재사용한다. - Garbage Collector : JVM의 Heap 영역에서 사용하지 않는 객체를 삭제하는 프로세스를 말한다.
- Native Method Interface(JNI)
- 네이티브 응용 프로그램 , C, C++와 같은 다른 언어로 작성된 어플리케이션과 연동할 수 있는 인터페이스를 제공
- 네이티브 응용 프로그램, C, C++ 라이브러리를 호출 할 수 있게 해줌
- 또한 네이티브 응용 프로그램, C,C++ 라이브러리가 호출 할 수 도 있게 해주는 역할도 수행
ex)
public static void main(String[] args) { Thread.currentThread(); }
Thread.currentThread(); 는 C로 구현한 메서드이다. 앞에 native 키워드가 있다.
- Native Method Libraries
- 네이티브 응용 프로그램 , C, C++ 와 같은 다른 언어들의 라이브러리를 의미
※ 네이티브 응용 프로그램 이란?
하드웨어와 운영 체제 플랫폼에 종속된 프로그램들을 말한다
.
JDK 와 JRE 의 차이
- JRE (Java Runtime Environment)
- 자바 실행 환경
- JVM이 자바 프로그램을 동작시킬 때 필요한 라이브러리 파일들과 기타 파일들을 가지고 있다.
- 즉, JVM의 실행환경을 구현해놓음
- 구성 : JVM + 표준 라이브러리(Java 2D, AWT, Swing ,CORBA , JDBC, JNDI .. 등)
- 이미 개발 된 프로그램을 실행만 할 경우
- JDK (Java Development Kit)
- 자바 개발도구
- 구성 : JRE + 개발에 필요한 도구(컴파일러 ,javadoc, java 등)
- 실행 뿐 아니라 자바 프로그램을 개발하고 싶을 때
- 오라클은 자바 11부터는 JDK만 제공하며 JRE를 따로 제공하지 않는다.
REFERENCE
이것이 자바다
자바의정석
더 자바, 코드를 조작하는 방법
https://www.theserverside.com/definition/Java-compiler
http://www.tcpschool.com/java/java_intro_programming
https://www.tutorialspoint.com/How-to-compile-a-java-program
https://wikidocs.net/257
https://www.ibm.com/cloud/learn/jre
https://stackoverflow.com/questions/1906445/what-is-the-difference-between-jdk-and-jre
https://www.softwaretestinghelp.com/java-components-java-platform-jdk/
http://javapracs.blogspot.com/2011/12/one-java-2-compilers-javac-and-jit.html
https://www.baeldung.com/java-class-view-bytecode'Java' 카테고리의 다른 글
[Java Study] - Garbage Collection(GC) in JVM (0) 2021.09.26 [Java Study] - LinkedList , Queue in Collection framework (0) 2021.09.26 [Java Study] - 연산자 , 연산자의 종류 (0) 2021.09.23 [Java Study] - 자바 데이터 타입, 변수 ,배열 (0) 2021.09.22 [Java] 문자열 앞뒤 공백 잘라내기- trim() (0) 2021.05.14