본문 바로가기

Programming/Java

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

목표

  • 자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기.

목차

  • JVM이란 무엇인가
  • 컴파일 하는 방법
  • 실행하는 방법
  • 바이트코드란 무엇인가
  • JIT 컴파일러란 무엇이며 어떻게 동작하는지
  • JVM 구성 요소
  • JDK와 JRE의 차이

 

 

1. JVM이란 무엇인가

JVM이란 Java Virtual Machine의 약자로 개발자가 작성하여 컴파일한 바이트코드를 실행하는 역할을 한다.

자바는 OS에 독립적인데 이것이 가능한 이유는, OS와 자바언어로 작성된 바이트코드 중간에 JVM이 존재하여 자바가 OS에 종속적이지 않게 바이트코드를 실행하기 때문이다. (즉, 자바는 OS에 독립적이나, JVM은 OS에 종속적이라고 할 수 있다.)

JVM은 바이트코드를 실행하는 표준이며 구현체이다. 또한 바이트코드를 OS에 특화된 머신코드로 변환하는 처리를 한다.(인터프리터와 JIT 컴파일러가 처리)

* 자바가 OS에 종속적이지 않다는 것을 증명하기 위해 뒤에서 windows 환경에서 컴파일한 클래스 파일을 macOS에서 실행해보자.

 

 

 

2. 컴파일 하는 방법

컴파일 전에 환경변수가 세팅되어 있는 지 확인하기

현재 환경변수에 설정된 JDK 버전을 확인하는 명령어: javac -version

환경변수가 제대로 설정되어 있으면 설정된 JDK의 컴파일러 버전이 표시된다. (macOS)

 

macOS 환경 기준으로 작성하였다. 윈도우의 경우는 아래와 같은 프로그램을 메모장으로 간단히 구현해보자.

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

 

vi 명령어로 간단한 자바 프로그램 작성하기(macOS)

 

명령어 : javac [파일명].java

예) javac Test.java

javac를 이용하여 자바 프로그램 컴파일하기(바이트코드로 변환)

컴파일이 완료되면 Test.class라는 파일이 생성되는데, 클래스파일 즉 바이트코드라는 파일이다.

 

 

 

3. 실행하는 방법

명령어 : java [클래스명]

예) java Test

java 명령어로 바이트코드를 실행

 

 

자바 프로그램이 OS로 부터 독립적인 것에 대한 확인

클래스파일(바이트코드)를 실행하는 도중 오류가 발생하였으니 오류메시지 확인해보자

윈도우 환경에서 컴파일된 바이트코드를 macOS에서 실행하였는데 위와 같은 오류가 발생하였다. 오류메시지를 읽어보면 컴파일에 사용된 자바버전이 실행환경보다 높아서 실행되지 않는 오류임을 알 수 있다.

사실 java.lang.UnsupportedClassVersionError 는 몇년 전 종종봐서 알고있던 오류이다. 개발환경 윈도우 장비는 JDK 8 버전을 설치한 상태에서 실제 개발 서버는 JDK 1.6을 사용중이여서 위와 같은 오류와 동일한 오류를 신입시절 겪어봤었다. 해당 오류를 바로 인지하여 해결하는 데에 오랜시간을 들이지는 않았었다. 

아래는 해당 오류 발생 시 자바 버전을 확인 할 수 있도록 숫자를 작성하였다.

  • Java SE 14 = 58
  • Java SE 13 = 57
  • Java SE 12 = 56 (0x38 hex)
  • Java SE 11 = 55 (0x37 hex)
  • Java SE 10 = 54
  • Java SE 9 = 53
  • Java SE 8 = 52
  • Java SE 7 = 51
  • Java SE 6.0 = 50
  • Java SE 5.0 = 49
  • JDK 1.4 = 48
  • JDK 1.3 = 47
  • JDK 1.2 = 46
  • JDK 1.1 = 45 

다음은 컴파일 환경과 런타임 환경에서 사용된 JDK 버전을 확인하는 과정이다.

윈도우 환경에서 설정된 자바 버전(컴파일환경)
macOS에서 확인한 자바 버전(실행환경)

해결방법은 간단하다. 윈도우 환경에서 컴파일 할 때 사용되는 JDK 버전을 낮추는 것이다. 최소한 실행환경과 같게 낮춰야할 필요가 있다. 또는 실행환경의 JDK버전을 컴파일 환경과 동일하게 올리는 것도 방법이다.

 

JDK 버전을 12에서 8으로 변경
JDK 버전 문제를 해결후 정상적으로 실행되는 화면

윈도우 환경은 아주 오래전에 JDK를 설치하고 사용을 안하다보니 어떤 버전을 설치하였는 지도 모르고 있었는 데, 해당 포스팅을 통해서 다시 확인할 수 있었다. 정리하면 JDK 버전은 컴파일 환경과 동일한 버전이거나 상위버전이여야 한다.(컴파일 <= 실행환경)

또한 윈도우 환경에서 컴파일하여 생성된 바이트코드를 macOS에서 실행함으로써 "자바가 OS에 독립적이다"라는 것을 확인하였다. 

 

 

 

4. 바이트코드란 무엇인가

바이트코드란 JVM에서 실행하기 위한 중간코드이다. 인터프리터는 바이트코드를 한 줄씩 읽어들이며 실행한다.

명령어 : javap -c [바이트코드명] (뒤에 .class는 생략한다.)

 

바이트코드 내용

바이트코드 맨 앞 줄을 확인하면 Code: 로 시작하는 값이 존재하는 데 1byte로 구성된 바이트단위의 명령코드이다. 1byte는 최대 256개의 상태를 표현할 수 있는 데, 현재 약 200여개의 명령어가 존재한다.

 

 

 

 

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

JIT 컴파일러는 Just In Time을 뜻하며 반복되는 바이트코드를 네이티브 코드로 변환하여 캐시에 저장 후 인터프리터가 해당 바이트코드를 만났을 때 별도로 바이트코드로 변환하지 않고 JIT 컴파일러가 미리 변환한 네이티브 코드를 즉시 호출한다. 여러 번 실행되는 바이트코드를 미리 네이티브 코드로 변환한다는 것은, 한 번만 실행되는 코드에 대해서는 인터프리터가 더 나은 결과를 나타낸다는 것을 예측할 수 있다.

더 나은 결과가 성능인지 속도인지 비용인지 혹은 이것들의 복합적인 측면인지는 너무 깊은 내용이여서 관련 자료를 찾아보고 링크를 추가해야할 필요성을 느낀다.

 

 

 

6. JVM 구성 요소(중요)

JVM의 구조

Class Loader 

  • 바이트코드( ~.class)에서 읽어들여 메모리에 저장한다.
  • Loading : 클래스를 읽어온다.
  • Linking : 레퍼런스를 연결한다.
  • Initialization : static 값을 초기화 한다.

Memory

  • Method Area : 클래스 수준의 정보가 담긴다.(클래스명, 변수, 메소드)
  • Stack : Thread 별 Runtime Stack을 생성하며, 내부에서 메소드 호출을 Stack Frame이라는 블럭으로 쌓는다. Stack Frame은  Method Call이다. Thread 종료 시 Runtime Stack도 제거된다.
  • PC Registers(프로그램 카운터 레지스터) : 각 Thread 들이 개별적으로 Thread 내에 현재 실행할 Stack Frame을 가리키는 포인터가 생성됨
  • Native Method Stack : Native 메소드를 호출 시 사용하는 Stack이다.
  • Heap : 객체가 저장되는 영역. 같은 객체는 공유한다.

Interpreter

  • 바이트코드를 한 줄씩 실행한다.

JIT Compiler

  • 불필요하게 여러번 반복되는 코드를 인터프리터가 발견하면 넘겨받아 네이티브 코드로 미리 변환 후에 인터프리터가 반복되는 코드를 발견 시 JIT 컴파일러로 변환된 네이티브 코드를 실행한다.

Native Method Stack(JNI)

  • 네이티브 메소드 라이브러리를 실행하기 위한 스택이다. native 키워드가 붙은 객체를 JNI라고 부르며 네이티브로 구현된 라이브러리를 호출할 수 있게 해주는 자바 인터페이스이다.

Native Method Library

  • 네이티브(C, C++ 등)로 구현된 라이브러리를 뜻한다.

GC

  • 가비지 컬렉터를 뜻하며, 더이상 사용하지 않는 객체를 메모리에서 제거하는 역할을 하며 이러한 행위를 가비지 컬렉션이라고 부른다.
  • 가비지 컬렉터의 종류로는 Serial GC, Parallel GC, CMS(JDK 9부터 deprecated. JDK 14부터 remove), G1GC, ZGC가 존재한다.
  • 가비지 컬렉터에 대한 자세한 내용은 별도의 포스팅에서 정리하고자 한다.(내용이 상당히 많을 것으로 예상됨)

 

7. JDK와 JRE의 차이

JDK는 Java Development Kit의 약자로 자바개발환경이라고 한다.

많은 기능이 있으나 대표적으로 개발자가 자바프로그램을 구현 후 컴파일하여 바이트코드를 생성하는 역할을 JDK가 한다.(정확히는 JDK의 구성 요소 중 하나인 javac이다.)

* javac는 설치 경로/bin 디렉터리 하위에 존재한다.(윈도우는 javac.exe 파일이다.)

 

JDK를 설치하면 JRE(자바실행환경)은 포함하고 있으므로 별도로 설치하지 않아도 된다.

 

JRE는 Java Runtime Environment의 약자로 자바실행환경이라고 한다.

자바 9 이후로는 JRE는 따로 배포되지 않는다. 이는 자바 9에 적용된 프로젝트 직쏘의 아주 일부분 이며, 프로젝트 직쏘에 대한 내용은 간단히 다음과 같다. (자세한 내용은 다른 포스팅에서 추가적으로 학습하도록 하자)

 

  • 라이브러리와 대규모 애플리케이션을 쉽게 구성하고 유지 관리 할 수 있음
  • 모듈화에 대한 최적화
  • JDK 보안 및 유지 관리
  • 애플리케이션의 성능 향상
  • 소형 디바이스 및 클라우드 배포를 위한 down scale

 

마무리

마무리 하기에는 너무 많은 내용을 설명할 수 있는 주제이고 기본이며 중요한 주제이다. 추가적인 포스팅을 작성하고자 하면 무수히 많은 포스팅을 할 수 있는 주제였다.

이번 포스팅 만큼은 주기적으로 추가/파생되는 포스팅을 작성하도록 해야겠다.

* 혹시 잘못된 정보가 있을 경우 댓글 남겨주시면 수정하도록 하겠습니다.

 

 

 

참조 링크

자바 버전에 해당하는 넘버 stackoverflow.com/questions/22489398/unsupported-major-minor-version-52-0

 

Unsupported major.minor version 52.0

Pictures: Command Prompt showing versions Picture of error Hello.java import java.applet.Applet; import java.awt.*; public class Hello extends Applet { // Java applet to draw "Hello World...

stackoverflow.com

JVM 구성요소 : www.inflearn.com/course/the-java-code-manipulation/dashboard

 

더 자바, 코드를 조작하는 다양한 방법 - 인프런

여러분이 사용하고 있는 많은 자바 라이브러리와 프레임워크가 "어떻게" 이런 기능을 제공할 지 궁금한적 있으신가요? 이번 강좌를 통해 자바가 제공하는 다양한 코드 또는 객체를 조작하는 방

www.inflearn.com

 

프로젝트 직쏘 :  openjdk.java.net/projects/jigsaw/

 

Project Jigsaw

Project Jigsaw The primary goals of this Project were to: Make it easier for developers to construct and maintain libraries and large applications; Improve the security and maintainability of Java SE Platform Implementations in general, and the JDK in par

openjdk.java.net

 

 

'Programming > Java' 카테고리의 다른 글

[기본-6] 상속  (0) 2021.03.03
[기본-5] 클래스  (0) 2021.03.03
[기본-4] 제어문  (0) 2021.03.02
[기본-3]자바 연산자  (0) 2021.03.01
[기본-2]자바 데이터 타입, 변수 그리고 배열  (0) 2021.02.28