LinkedIn

자바 스터디 1주차 : JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.

2020. 11. 8. 18:47 | 자바 개발자되기

Why?

 

1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가. · Issue #1 · whiteship/live-study

목표 자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기. 학습할 것 JVM이란 무엇인가 컴파일 하는 방법 실행하는 방법 바이트코드란 무엇인가 JIT 컴파일러란 무엇이며 어떻게 동작하는지 JV

github.com

학습 진행 방법

  • 전체적인 내용은 학습 목차를 포함하지만 내용의 순서는 학습 목차와 다를 수 있으며 학습을 진행하며 공부 한 순서에 따라 내용 기술
1. JVM이란 무엇인가
2. JVM 구성요소
3. 자바 컴파일 및 실행 방법

학습 목차

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

 

 


1. JVM이란 무엇인가

A Java virtual machine (JVM) is a virtual machine that enables a computer to run Java programs as well as programs written in other languages that are also compiled to Java bytecode. - wikipedia

자바 가상 머신은 컴퓨터가 자바 프로그램을 실행할 수 있도록 도와준다.

 

자바 프로그램을 바로 실행 할 수는 없는 것 일까?

  • 없다. 컴퓨터가 이해 할 수 있는 언어는 기계어로 0과 1로 이루어진 바이너리 코드이다. 그에 비해 자바 프로그램(컴파일 된)은 바이트 코드(가상 머신이 이해할 수 있는 코드)로 되어 있다.

바이너리 코드와 바이트 코드

바이너리 코드

  • 0과 1로 구성되어 있는 코드
  • C언어로 작성 된 .c 파일을 컴파일한 .obj 파일이 바이너리 코드
    • 하지만 .obj 파일만으로는 실제 컴퓨터가 이해하여 실행할 수 없다. 이때 필요한 것이 링커로 링커는 여러 개의 코드와 데이터를 모아서 연결하여 메모리에서 실행 가능 한 파일로 만드는 역할을 한다.
    • 위 과정이 모두 진행된 후 생성되는 실행 파일이 컴퓨터가 이해 할 수 있는 기계어로 구성

바이트 코드

  • 0과 1로 구성되어 있는 이진 코드이지만 바이너리 코드와 다르게 가상 머신이 이해할 수 있는 코드
  • 사람에게 더 친숙한 고급언어보다는 덜 추상적이지만 기계어보다는 추상적이다.
  • 컴퓨터가 이해 할 수 있는 기계어로 만들기 위해서는 인터프리터의 도움이 필요하다.

컴퓨터가 이해 할 수 있는 언어는 기계어라는 것을 알았다.

 

그렇다면 도대체 JVM은 왜 필요한 것 일까?

기계어는 하나의 언어가 아니다

  • 컴퓨터, 정확히 말하자면 CPU가 이해할 수 있는 언어 기계어는 하나의 언어가 아니다.
  • CPU 제조사마다 다르기에 특정 프로그램 A를 X, Y, Z라는 각각 다른 컴퓨터 환경에서 실행하려면 각각의 제조사에 맞는 기계어를 알고 있어야 한다.

그렇다면 개발자는 모든 종류의 CPU에 맞는 기계어 패턴을 알고 있어야 할까?

  • 하드웨어 엔지니어가 아닌 이상 일반적인 소프트웨어 엔지니어의 목표는 요구 사항을 충족하는 프로그램을 개발하는 것이다.
  • CPU 제조사마다 다른 기계어 패턴을 알 필요 없이 요구 사항을 충족하는 프로그램을 하나의 고급 언어로 작성하는 것이 이상적일 것이다.

 

자바 가상 머신이란 컴퓨터가 자바 프로그램을 실행할 수 있도록 도와준다.

  • 결국 JVM은 자바 프로그램(바이트 코드)을 다양한 CPU 환경에서 이식성 문제없이 실행할 수 있도록 도와주는 가상 머신

2. JVM 구성 요소

JVM은 크게 클래스 로더 시스템, 메모리, 실행 엔진, 그리고 네이티브 메서드로 나뉘어져 있다.

 

클래스 로더 시스템

을 알아보기 전에 자바 소스 프로그램이 컴파일되어 실행되기까지의 순서를 간략하게 확인

  1. 개발자가 자바 언어를 사용하여 프로그램 작성 .java
  2. 작성 한 프로그램을 컴파일 .class
  3. 프로그램 실행에 필요한 .class 파일들을 모두 읽어 연결
  4. 프로그램 실행 전 메모리 초기화 작업 진행
  5. 바이트 코드로 작성된 프로그램을 인터프리터가 기계어로 번역하여 실행

 

  • 클래스 로더 시스템은 컴파일된 바이트코드들을 읽어 연결한 뒤 메모리에 저장하는 역할을 수행
  • 내부적으로는 로딩, 링크, 초기화의 단계가 존재
  • 클래스 로더 시스템 초기화 단계에서 전역 변수를 메모리에 할당하기 때문에 필요 이상으로 전역 변수를 남용할 경우 메모리 이슈를 겪을 수 있음

 

실행 엔진

클래스 로더 시스템에 의하여 실행에 필요한 준비 과정이 완료되었다면 이제 인터프리터를 사용하여 바이트 코드를 번역하여 실행할 차례이다.

실행 엔진 내부적으로는 인터프리터, JIT 컴파일러, GC가 있다.

  • 인터프리터
    • 컴파일된 .class의 바이트 코드를 실행하는 역할
  • JIT 컴파일러
    • 프로그램이 실행될 때 인터프리터가 바이트코드를 읽어 기계어로 번역하지만 프로그램에는 반복적으로 사용하는 코드가 존재한다.
    • 반복적으로 사용되는 코드를 매 번 번역하는 것보다는 최초 1회만 번역하여 특정 저장소(캐시)에 저장 한 뒤 추가 참조가 필요할 때마다 불러온다면 성능 향상을 이끌어 낼 수 있을 것이다.
    • 이 역할을 수행하는 것이 JIT 컴파일러이다.
  • GC
    • 프로그램이 실행되면서 특정 데이터를 저장할 때 주로 메모리를 사용한다.
    • 다양한 로직이 순차적으로 실행되다 보면 한정돼있는 메모리는 여러 데이터로 점령될 것이다.
    • 더 이상 참조되지 않는 데이터를 정리하는 역할을 수행하는 것이 GC이다.

 

JIT 컴파일러

일반적으로 인터프리터 언어(python)보다는 정적 컴파일 언어(C)가 실행 속도가 더 빠르다고들 한다.

 

왜 그럴까?

 

그 이유는 JIT 컴파일러의 목적을 보면 알 수 있다.

정적 컴파일 언어의 경우 컴파일에 시간이 오래 걸리는 반면 컴파일 후 결과물(.exe)은 CPU가 이해할 수 있는 기계어이기 때문에 실시간으로 번역하여 실행하는 인터프리터 언어보다 빠를 수 밖에 없다.

  • Java는 컴파일 언어이지만 동적 컴파일 언어이다.
    • CPU가 이해할 수 있는 기계언어가 아닌 JVM이 이해 할 수 있는 바이트 언어로 컴파일한 뒤 인터프리터에 의해 실시간으로 번역되어 실행된다.

JIT 컴파일러는 반복되어 사용되는 코드나 기계어로 변환 시 많은 리소스가 필요한 부분을 코드가 실행되는 과정(Just-In-Time)에 실시간으로 변환(기계어)하여 캐싱한다.

 

Java는 이러한 최적화 과정이 존재하기에 인터프리터 언어(Python) 보다 좋은 실행 성능을 낼 수 있다.

 

메모리

스택

  • FILO의 특징을 갖고 있는 스택 구조는 특정 영역에서 사용되는 메모리 프레임을 만들 때 사용된다.
  • 특정 스레드가 생성될 때마다, 특정 함수가 호출 될 때 마다 각각의 스택 프레임을 만들고, 함수 파라미터와 같은 데이터를 저장할때는 데이터를 역순으로 저장한다.
    • 역순으로 저장하는 이유는 FILO의 특징 때문

  • 힙에는 대표적으로 객체(메모리 할당된 인스턴스)가 저장된다.
  • GC의 주 대상이 되며 Application Context 전반적으로 공유되는 자원이다.

PC

  • 현재 실행 중인 명령어의 주소와 Return Address를 저장하는 register로써 하나의 스레드가 생성될 때마다 독립적으로 존재한다.

네이티브 메서드 스택

  • 네이티브 메서드(C, C++ 등 자바 이외의 언어로 작성 된 코드)가 저장되는 메모리 공간

메소드

  • 클래스의 정보나 static 변수가 저장되어 있으며 Application Context 전반적으로 공유되는 영역

3. 자바 컴파일 및 실행 방법

자바 소스를 컴파일 및 실행하기 위해서는 기본적으로 아래의 두 프로그램이 필요하다.

  1. javac.exe
  2. java.exe

javac.exe는 자바 소스코드를 컴파일할 때 사용하는 프로그램이며 컴파일된 바이트 코드를 실행할 때 java.exe 사용

 

또한 javac.exe는 JDK, java.exe는 JRE에 포함되어 있기에 JDK과 JRE를 설치해야 하지만 과거와 다르게 요즘은 JDK에 JRE가 포함된 형태로 배포되고 있기에 JDK만 설치해도 무관

JDK

  • Java Development Kit로 오라클 자바 11부터는 JRE 포함하고 있으며 개발에 필요한 여러 가지 툴을 제공

JRE

  • Java Runtime Environment로 바이트 코드로 컴파일된 자바 프로그램을 실행할 때 사용

컴파일 방법

  1. 자바 소스 파일 작성 .java
  2. javac.exe 사용하여 .java 파일 컴파일
$ javac 소스파일명.java

→ 컴파일이 정상적으로 완료되면 해당 경로에 소스파일명.class 생성

 

실행 방법

java.exe 파일을 사용하여 바이트코드로 컴파일 된 .class 실행

  • 단, 실행 시에는 소스 파일명의 확장자는 붙이지 않음
$ java 소스파일명

참고

 

Java JVM Run-time Data Areas - Javapapers

Understanding Java Virtual Machine (JVM) run-time data areas are critical to better Java programming. One of the most dreaded errors in Java is OutOfMemoryError and it is related to Java Virtual Machine (JVM) memory areas. We should have better understandi

javapapers.com

 

JIT 컴파일 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 둘러보기로 가기 검색하러 가기 JIT 컴파일(just-in-time compilation) 또는 동적 번역(dynamic translation)은 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일

ko.wikipedia.org

 

자바 가상 머신 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 자바 가상 머신 사양의 자바 SE 7 에디션에 기반을 둔 자바 가상 머신(JVM) 아키텍처의 개요도. 자바 가상 머신(영어: Java Virtual Machine, JVM)은 자바 바이트코드를 실

ko.wikipedia.org

 

[기본] 바이트코드와 바이너리코드-

ㅁ C언어는 컴파일러에 의해 소스파일(*.c)이 목적파일(*.obj)로 변환될 때 바이너리 파일이 됨.  ㅇ"바이너리 파일이 된다"는 것은 숫자 0과 1로 이루어진 코드로 변환됨을 의미.(마치 매트릭스)  

jojuim.tistory.com