[1주차] JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가

janjanee·2022년 8월 1일
0
post-thumbnail

2020.12.20 작성글을 이전

1. JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가

학습 목표 : 자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기

JVM(Java Virtual Machine)이란?

  • JVM은 Java Virtual Machine의 약자로 자바 컴파일러가 변환한 바이트코드를 실행 시키는 프로그램이다.

  • JVM은 OS를 대신해서 자바 프로그램을 실행하는 가상의 운영체제 역할을 한다.

    따라서, 개발자는 운영체제와 상관없이 자바 프로그램을 개발하고 재사용 할 수 있다.

  • 메모리 관리, Garbage Collection을 수행한다.

컴파일 방법과 실행

  • 컴파일이란?

    사람이 이해하는 언어를 컴퓨터가 이해할 수 있는 언어로 변환하는 과정

JVM은 자바 컴파일러가 변환한 바이트코드를 실행한다고 했다. 즉, 자바의 컴파일이란 JVM이 이해할 수 있는 바이트코드로 변환하는 것을 뜻한다.

그렇다면, 컴파일러를 통해 컴파일을 어떻게 하는 것인지 알아보자.

컴파일 하는 방법 전에 순서는 다음과 같다.

  1. .java 소스 파일 작성

  2. 컴파일러(javac.exe)로 바이트코드 파일(.class)생성

  3. JVM 구동 명령어(java.exe)로 실행

1. .java 소스 파일 작성

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello Java");
    }
}

인텔리제이, 이클립스와 같은 IDE나 에디터를 이용하여 Hello.java 파일을 생성한다.

2. 컴파일러로 바이트코드 파일 생성

javac Hello.java

javac [파일명].java 명령어를 통해서 자바 소스 파일을 컴파일 한다.

Hello.java
Hello.class // 컴파일을 통해 생성된 파일

에러없이 컴파일이 정상적으로 완료됐다면 해당 폴더에 Hello.class라는 컴파일된 파일이 한 개 생성된 것을 확인할 수 있다.

.class 파일 내부를 열어보면 바이트코드라 사람이 알아보기 어렵다.

javap -c Hello.class

JDK에 내장되어있는 javap 역어셈블러를 통해 사람이 읽기 쉬운 형태로 볼 수 있다. -c 옵션은 클래스의 각 메소드에 대해 역어셈블된 코드를 제공한다.

3. JVM 구동 명령어(java.exe)로 실행

java Hello

마지막으로 JVM 구동 명령어인 java 파일명을 입력하면 정상적으로 프로그램이 실행된다. 이 때, 주의할점은 확장자를 포함하면 안되고, 대소문자 구분을 정확하게 해야한다.

😀 그러나! 현실적으로, 우리는 IntellJ, 이클립스와 같은 IDE를 통해 자바 프로그램을 실행한다.

바이트코드란 무엇인가

바이트코드

  • 바이트코드(Bytecode, portable code, p-code란 특정 하드웨어가 아닌 가상 컴퓨터에서 돌아가는 실행 프로그램을 위한 이진 표현법이다.

자바 바이트코드

  • 자바 바이트코드는 자바 가상머신(JVM)이 실행하는 명령어의 형태이다.

  • 각각의 바이트코드는 1바이트로 구성되지만 몇 개의 파라미터가 사용되는 경우가 있어

    총 몇 바이트로 구성되는 경우가 있다.

  • 자바 바이트코드 확장자는 .class 이다.

왜 바이트코드를 쓰는가?

자바는 이식성이 높은 언어를 만들기 위해 출발됐다. 이식성이란? 여러 다른 환경의 운영체제나 시스템에서 동일한 코드를 사용할 수 있도록 하는 것이다.

이식성을 위해 자바는 바이트코드를 사용했고, 이를 해석하기 위한 가상 컴퓨터 역할을 하는 JVM을 사용한다.

JIT 컴파일러란 무엇이며 어떻게 동작하는지

JIT 컴파일러란?

JIT 컴파일러(Just In Time Compiler)는 프로그램을 실제 실행하는 시점에 (실시간에) 기계어로 번역하는 컴파일 기법이다.

JIT 컴파일러는 바이트코드를 읽어 빠른 속도로 기계어를 생성할 수 있다. 이 과정이 실시간으로 일어나서 (Just-In-Time) 이다.

또한, 전체 코드의 필요한 부분만 변환한다 기계어로 변환된 코드는 캐시에 저장되기 때문에 재사용시 컴파일을 다시 할 필요가 없다.

JIT 컴파일러 동작원리

  1. 자바 컴파일러가 자바 소스 코드를 바이트코드로 변환
  2. 바이트코드 실행 시점에 JVM이 JIT 컴파일러를 통해 바이트코드 -> 기계어(Native code)로 변환

위의 그림에서 컴파일 타임과 런타임은 무엇을 의미할까?

컴파일 타임 (Compile tile)

  • 개발자에 의해 소스코드가 작성되며, 작성된 소스코드를 컴퓨터가 인식 할 수 있는 기계어(자바에서는 JVM이 인식할 수 있는 바이트코드)로 변환되어 실행 가능한 프로그램이 되는 과정

런타임 (Run time)

  • 컴파일 과정을 마친 응용 프로그램이 사용자에 의해 실행되어지는 때(time)

JVM 구성 요소

출처 : https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94_%EA%B0%80%EC%83%81_%EB%A8%B8%EC%8B%A0

JVM 구성 요소는 다음과 같이 크게 네 가지로 나뉜다.

  1. Class Loader

  2. Runtime Data Area = JVM Memory

  • Method Area (Class Area, Code Area, Static Area)
  • Heap Area
  • Stack Area
  • PC registers
  • Native Method stack
  1. Excution Engine

  2. Native

Class Loader

클래스 로더는 로딩, 링크, 초기화 순서로 진행된다. 클래스 로더는 클래스 파일을 적재(Runtime Data Area에)하는 역할을 한다.

  • 로딩 : 클래스 로더는 .class 파일을 읽어들여서 메서드 영역에 저장한다. (FQCN(Full Qualified Class Name), 클래스, 인터페이스, Enum, 메서드와 변수) 로딩이 끝나면 Class 객체를 생성 후, 힙 영역에 저장한다.
    • Boostrap 클래스 로더 : JAVA_HOME\lib에 있는 코어 자바 API를 제공한다. 최상위 우선 순위를 가진 클래스 로더
    • Extension(Java 9 부터 Platform) 클래스 로더 : jre/lib/ext 폴더나 java.ext.dirs 환경 변수로 지정된 폴더에 있는 클래스 파일을 로딩
    • Application(Java 9 부터 System) 클래스 로더 : 애플리케이션 클래스패스 -classpath나 java.class.path 환경 변수의 값에 해당하는 위치에서 클래스를 로딩
  • 링크
    • Verify : .class 파일의 유효성 체크
    • Prepare : 클래스 변수와 기본값에 필요한 메모리 준비
    • Resolve : 심볼릭 메모리 래퍼런스를 메서드 영역에 있는 실제 래퍼런스로 교체
  • 초기화 static 변수의 값을 할당한다. (static 블럭의 실행시점)

Runtime Data Area

클래스 파일들의 적재장소이며 총 다섯가지 영역이 있다.

  • Method Area : 클래스 멤버 변수명, 데이터 타입, 리턴 타입, 상수풀, static 변수등이 저장. (공유영역)

  • 힙 영역 : new 연산자를 통해 생성된 객체와 배열이 저장. (공유영역)

  • 스택 영역 : 스레드가 생성 될 때마다 생성되는 영역. 대표적으로는 지역변수가 저장.

    메서드 호출 시 -> 스택 개별 생성.

  • PC Register : 스레드가 생성될 때 마다 생성되는 영역. 현재 스레드가 실행되는 부분의

    주소와 명령을 저장. 스레드 생성 시 메서드와 힙 영역은 모든 스레드가 공유한다.

    그러나 PC Register, 스택 영역, Native Stack Area는 공유되지 않음.

  • Native Method Stack : 자바 언어 이외의 언어로 작성된 코드를 저장하는 메모리 영역.

Execution Engine

클래스 로더를 통해 Runtime Data Area로 적재된 클래스(바이트코드)들을 기계어로 변경하여 실행하는 역할을 한다. 이때 명령어를 하나씩 실행하는 인터프리터 방식과 바이트 코드를 네이티브 코드로 변환하는 JIT Compiler 방식이 있다.

Garbage Collector (GC)

힙 영역에 생성되는 객체중에 참조되지 않는 객체들을 메모리에서 제거한다. GC를 실행하는 스레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다.

JDK와 JRE의 차이

JDK -> JRE + Development Kit JRE -> JVM + Library

  • JRE(Java Runtime Enviroment)는 자바 프로그램을 실행시켜주는 환경을 구성해주는 도구이다. 말 그대로 실행을 시켜주는 환경을 구성할 뿐 JRE만 가지고서는 자바 개발을 할 수 없다.
  • JDK(Java Development Kit)는 자바 개발에 필요한 개발 키트를 제공한다. 개발도구 + 실행(JRE)로 구성되어있다.

따라서, 자바 개발을 하려면 JDK가 필요하다.

자바 11 부터 JRE를 제공하지 않는다. JDK 안에 JRE가 포함되어있으니 JDK를 사용하면 된다.

References

profile
얍얍 개발 펀치

0개의 댓글