JVM의 개념과 JDK/JRE

이기영·2024년 5월 22일

Java 기초학습

목록 보기
1/14
post-thumbnail

목표

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

목차

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


1. JVM이란 무엇인가?

Java Virtual Machine. 자바를 실행하기 위한 자바 가상머신

.java 파일을 컴파일러를 통해 .class 파일(ByteCode)로 만들고, 이를 운영체제가 이해할 수 있는 기계어로 바꿔주는 역할을 합니다.

이러한 JVM은 운영체제에 영향을 받지 않고 실행이 가능하도록 해줍니다.

JVM Specification Image

Java Virtual Machine (JVM) 구조(위키 백과)


실행순서

  1. 프로그램이 실행되면 JVM은 운영체제로부터 실행하려는 프로그램이 필요로 하는 메모리에 할당 받습니다.
    (JVM은 이 메모리를 용도에 맞게 여러 영역으로 나누어 관리합니다.)

  2. 자바의 컴파일러(javac)가 소스코드(.java)를 읽어들여 자바 바이트코드(.class) 형식으로 바꿔줍니다.

  3. Class Loader를 통해 class 파일을 JVM Memory에 적재합니다.

  4. JVM Memory 영역에 적재된 class 파일을 Excution Engine을 통해 해석합니다.

2. 컴파일 하는 방법

준비물 : java.exe , javac.exc

 javac.exe는 자바 소스코드를 컴파일 할때 사용하는 프로그램 입니다. 이때 만들어진 .class(바이트코드 파일) 을 실행하는게 java.exe 입니다.

$ javac 소스파일명.java

 위와 같이 명령어를 입력하여, .class 파일을 생성할 수 있습니다.
만들어진 .class 파일은 같은경로에 생성되며, 이름 또한 소스파일명.java의 소스파일 명을 따라갑니다.

참고

컴파일러(javac.exe)와 실행파일(java.exe)의 JDK/JRE 버전은 일치해야 합니다. 컴파일 옵션을 통해 해결하는 방법도 있긴합니다.


3. 실행하는 방법

$ java 소스파일명

위와 같은 명령어를 통해 java.exe 를통해 바이트 코드로 컴파일된 .class를 실행 할 수 있습니다.


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

 프로그램을 실행하는것은 컴퓨터이기 때문에, 컴퓨터가 이해할 수 있는 기계어를 전달해주어야 합니다.


1) 바이너리 코드란?

  • 0과 1로 구성되어 있는 코드 입니다.
  • C언어로 작성 된 .c 파일을 컴파일한 .obj 파일이 바이너리 코드입니다.

    하지만, .obj 파일은 완벽한 기계어는 아닙니다. 이 파일을 완벽한 기계어로 변환하려면 "링커"가 필요한데, 이 링커는 여러 개의 코드와 데이터를 모아 연결하여 메모리에서 실행 가능한 파일로 만드는 역할을 해줍니다.

※ 즉, 기계어는 컴퓨터가 이해할 수 있는 0과 1로 이루어져있는 바이너리 코드이지만, 기계어가 바이너리 코드로 이루어졌을 뿐이지, 모든 바이너리코드가 기계어인것은 아닙니다!


2) 바이트 코드

  c언어와 다르게 Java에서는 컴파일러(javac)에 의해 소스파일(.java)이 바이트코드(.class)가 되는데, 컴퓨터는 이 바이트 코드를 바로 인식할 수는 없습니다.


이 바이트 코드를 인식할 수 있는게 바로 가상머신입니다. JVM을 통해 컴퓨터에게 코드를 전달 할 수 있는것입니다.

그럼 왜? 귀찮게 이러한 과정을 거치는가.

JVM이 설치되어있다면, 그게 어떤 플랫폼이라도 실행을 할 수 있게 되기 때문입니다. 즉, 이 JVM을 통해 운영체제의 종류나, 개발이 수행되는 환경의 종류에 구애받지 않고, 프로그램을 실행할 수 있게 됩니다.



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

JIT?

C나 C++처럼 프로그램을 실행하기 전에 처음 한 번 컴파일 하는 대신, 프로그램을 실행하는 시점에서 필요한 부분을 즉석으로 컴파일 하는 방식을 말합니다. (Just-In-Time)

  JIT 컴파일러는 바이트코드를 읽어 빠른 속도로 기계어를 생성할 수 있습니다. 이런 기계어 변환은 코드가 실행되는 과정에 실시간으로 일어나며(Just-In-Time), 전체 코드의 필요한 부분만 변환합니다. 기계어로 변환된 코드는 캐시에 저장되기 때문에 재사용시 컴파일을 다시 할 필요는 없습니다.


6. JVM 구성요소

JVM Specification Image

Java Virtual Machine (JVM) 구조(위키 백과)


1) Class Loader

클래스 로더는 자바 바이트코드(.class)를 읽고 JVM 내로 클래스를 로드하는 역할을 합니다. 클래스 파일을 찾고, 읽고, 검사한 후, JVM의 메모리 영역에 적재합니다. 주된 작업은 다음과 같습니다.

  • 로딩(Loading): 클래스 파일을 찾아 읽어들입니다.
  • 링킹(Linking): 클래스 파일의 유효성을 검증하고, 참조를 해결하며, 메모리를 할당합니다.
  • 초기화(Initialization): 클래스 변수들을 초기화하고 static 블록을 실행합니다.

2) JVM Memory

JVM 메모리는 프로그램 실행 중에 필요한 데이터를 저장하는 여러 메모리 영역으로 나뉩니다.

  • Method Area(메소드 영역): 클래스 메타데이터, 상수 풀, 스태틱 변수, 메소드 코드 등이 저장됩니다. 일반적으로 퍼머넌트 제너레이션(PermGen) 또는 메타스페이스(Metaspace)로 구현됩니다.
  • Heap(힙): 모든 객체 인스턴스와 배열이 저장되는 영역입니다. 가비지 컬렉터가 이 영역을 관리하며, Young Generation과 Old Generation으로 나뉩니다.
  • JVM Language Stacks(JVM 언어 스택): 각 스레드마다 존재하며, 메소드 호출 시 생성되는 프레임을 저장합니다. 프레임에는 지역 변수, 피연산자 스택, 메소드 호출/복귀 정보가 포함됩니다.
  • PC Resgisters(PC 레지스터): 각 스레드마다 존재하며, 현재 실행 중인 JVM 명령의 주소를 저장합니다.
  • Native Method Stacks(네이티브 메소드 스택): 네이티브 메소드(자바 이외의 언어로 작성된 메소드) 호출시 사용되는 스택입니다.

3) Execution Engine(실행 엔진)

실행 엔진은 바이트코드를 실제로 실행하는 역할을 합니다. 실행 엔진은 다음의 세 가지 주요 구성 요소로 이루어져 있습니다.

  • Interpreter : 바이트 코드를 한 줄씩 읽고 실행합니다. 처음에는 빠르게 실행할 수 있지만, 반복문 등에서 속도가 느려질 수 있습니다.
  • JIT Compiler : 인터프리터의 단점을 보완하기 위해, 자주 사용되는 코드(핫스팟)를 기계어로 변환하여 실행 속도를 높입니다. 컴파일된 코드는 캐시에 저장되어 이후 빠르게 실행됩니다.
  • Garbage Collector: 힙 영역을 관리하며, 사용되지 않는 객체를 자동으로 메모리에서 해제하여 메모리 누수를 방지합니다.

✨ Garbage Collector의 역할

  • 객체 할당: 새 객체가 생성될 때 힙 영역에 메모리를 할당합니다.
  • 객체 수집: 더 이상 참조되지 않는 객체를 식별하고 메모리를 회수합니다.
  • 메모리 정리: 힙 영역의 단편화를 줄이기 위해 메모리를 정리하고 재배치합니다.

4) Native Method Interface

네이티브 메소드 인터페이스는 자바 코드에서 네이티브(비자바) 코드를 호출할 수 있도록 해주는 프레임워크입니다. 주로 C, C++로 작성된 네이티브 라이브러리와 상호작용할 때 사용됩니다.


5) Native Method Libraries

네이티브 메소드 라이브러리는 JVM이 네이티브 메소드 인터페이스를 통해 호출할 수 있는 네이티브 코드로 작성된 라이브러리입니다. 예를 들어, 자바에서 시스템 레벨의 기능을 사용하기 위해 운영체제 API를 호출할 때 사용됩니다.

세줄요약

  1. JVM은 자바 애플리케이션을 실행하기 위한 시스템
  2. Class Loader는 클래스 파일을 로드하고, JVM Memory는 실행 중 필요한 데이터를 저장하며, Execution Engine은 바이트코드를 실제로 실행함.
  3. Native Method Interface와 Native Method Libraries는 자바의 코드와 네이티브 코드를 연결하는 부가적이며 강력한 기능을 함.



7. JDK와 JRE의 차이

1) JDK

JDK는 자바 개발도구(Java Development Kit)의 약자입니다. Java로 애플리케이션을 개발하고 컴파일할 수 있도록 해주는 개발 환경의 세트를 의미합니다. JDK는 다음과 같은 구성 요소를 포함합니다:

  • javac: 자바 컴파일러로, 자바 소스 코드를 바이트코드로 컴파일합니다.
  • java: 자바 애플리케이션을 실행하는 명령어입니다.
  • jar: 자바 아카이브 도구로, 여러 클래스 파일을 하나의 압축 파일로 묶습니다.
  • javadoc: 자바 소스 코드에서 API 문서를 생성하는 도구입니다.
  • visualVM: 자바 애플리케이션의 모니터링, 디버깅, 프로파일링을 위한 도구입니다.
  • 기타 유틸리티: 다양한 개발 도구와 유틸리티를 포함하여 개발 과정에서 필요한 여러 기능을 제공합니다.

JDK는 JRE(Java Runtime Environment)를 포함하며, 개발에 필요한 도구들을 추가적으로 제공합니다. 따라서, 자바 애플리케이션을 개발하고 실행할 수 있는 완전한 환경을 제공하는 것이 JDK입니다.

JRE

JRE는 자바 실행환경(Java Runtime Environment)의 약자입니다. 자바 애플리케이션을 실행할 수 있는 환경을 제공합니다. JRE는 다음과 같은 구성 요소를 포함합니다:

  • JVM (Java Virtual Machine): 자바 바이트코드를 실행하는 가상 머신으로, 플랫폼 독립적인 실행 환경을 제공합니다.
  • 클래스 라이브러리: 자바 표준 라이브러리로, 자바 애플리케이션이 사용하는 다양한 클래스와 인터페이스를 포함합니다. 예를 들어, 컬렉션 프레임워크, I/O, 네트워킹, GUI, 유틸리티 클래스 등이 포함됩니다.
  • 구성 파일 및 설정: JVM과 클래스 라이브러리의 동작을 제어하는 구성 파일과 설정을 포함합니다.

JRE는 자바 애플리케이션을 개발할 필요는 없지만, 자바 애플리케이션을 실행할 수 있는 환경을 제공합니다. 따라서, 자바 애플리케이션을 실행하려는 사용자나 서버 환경에서는 JRE만 설치하면 충분합니다.

profile
안녕나를소개하지이름은HaBu직업은Programer취미는tai chi meditation

2개의 댓글

comment-user-thumbnail
2024년 5월 27일

아주 유익한 글이네요. 붐업

1개의 답글