새소식

프로그래밍 언어/JAVA

자바 기초 - 2. JVM에 대한 모든 것

  • -

❗ 읽기 전 알아두면 좋은 용어


  • 소스 코드 (Source Code) : 사람이 읽을 수 있는 코드로 보통 컴퓨터 소프트웨어(프로그램)를 프로그래밍 언어로 기술한 것을 의미
  • 바이트 코드 (Byte Code) : 소스 코드를  컴파일하여 가상머신이 이해할 수 있도록 만든 중간 코드
  • 기계어 (Machine Code) : 컴퓨터(CPU)가 별다른 해석 없이 바로 읽을 수 있는 코드, 네이티브 코드라고도 합니다.

 

 

💻 JVM이란?


Java Virtual Machine의 약자로, 자바로 개발된 프로그램을 실행하기 위한 가상 컴퓨터를 의미합니다.

 

조금 더 자세히 말해보자면, JVM은 자바로 개발된 프로그램을 컴파일하여 만들어지는 자바 바이트 코드를 해석하고 실행하는 역할을 합니다.

 

자바와 OS 사이에서 중개자 역할을 하며, OS에 구애받지 않고 독립적으로 실행시킬 수 있게 해주는 꼭 알아둬야할 친구입니다.

 

더 자세하게 알아보기 위해서는 자바 프로그램이 컴퓨터에서 어떻게 실행되는지 알아야 합니다.

 

🎢 자바 프로그램의 실행 단계


자바로 작성된 프로그램은 아래와 같은 과정을 거쳐 실행되게 됩니다.

 

 

출처 :http://net-informations.com/java/intro/jvm.htm

 

1. 자바로 소스 코드(. java)를 작성합니다.

2. 자바의 컴파일러(javac)가 소스코드를 컴파일하여 바이트 코드(. class)를 만듭니다.

3. 운영체제별 JVM은 해당 운영체제에 맞는 기계어로 번역 후 실행합니다.

 

결과적으로 자바는 JVM을 통해 하나의 바이트 코드로 다양한 환경에서 동일한 결과를 보장합니다.

 

위의 이미지에서 보면 JVM은 운영체제에 종속되어있는데, 이는 자바의 특징 중 하나인 Multi-Platfom을 지원하는 요소입니다.

 

따라서, JVM은 운영체제에 맞게 설치되어야 하며 운영체제별로 제공되는 JDK 또는 JRE를 설치하면 자동으로 설치가 됩니다.

 

 

 

🧱 JVM 구조


그렇다면 JVM의 내부 구조는 어떤 식으로 작동할까요?

 

 

JVM은 크게 세가지 주요 하위 시스템으로 나누어집니다.

 

🚢 Class Loader


 .class 파일에서 바이트 코드(바이너리 코드)를 읽어 메모리에 올려주는 역할을 합니다.

 

컴파일 시점이 아닌 런타임 시점에 클래스를 로딩(동적 로딩)하며, 클래스의 인스턴스를 생성하면 클래스 로더를 통해 메모리에 로드하게 됩니다.

 

간단히 말하자면 이름 그대로 런타임 중에 JVM의 메소드 영역에 동적으로 자바 클래스를 로드하는 역할을 합니다.

 

클래스 로더는 총 세가지 과정을 거칩니다.

 

 

Loading

클래스 파일을 JVM에 올려주는 과정으로 총 세가지 종류의 클래스 로더를 사용하여 진행됩니다.

  1. Bootstrap Class Loader : 가장 필수가 되는 Library class를 load
  2. Extension Class Loader : Bootstrap class 다음으로 중요한 class를 load
  3. Application Class Loader(= System Class Loader) : 개발자가 작성한 class를 load

로딩 과정은 하위 클래스 로더부터 상위 클래스 로더로 요청받은 클래스가 있는지 찾도록 위임하게 됩니다.

상위 클래스 로더에 존재하지 않는다면, 하위 클래스 로더를 찾는 식으로 이루어지게 됩니다.

 

여기서 모든 클래스들은 각각 하나의 클래스 로더에서만 로드될 수 있고 하위 클래스 로더는 상위 클래스 로더가 로드한 클래스를 볼 수 있지만, 반대로 상위 클래스 로더는 하위 클래스 로더가 로드한 클래스를 알 수 없습니다.

 

위와 같은 과정을 거친 후 로딩된 클래스의 바이트 코드를 메소드 영역에 저장되게 됩니다.

 

만약, 메소드 영역에 이미 클래스가 로딩되어 있다면 그것을 사용하게 되고 최종적으로 클래스를 찾지 못하는 경우, ClassNotFoundException이 발생하게 됩니다.

 

여기서 알아두면 좋을만한 내용으로는 로드 타임 동적 로딩, 런타임 동적 로딩이 있습니다.

로드 타임 동적 로딩 : 하나의 클래스를 로딩하는 과정에서 그 클래스가 필요로하는 다른 클래스를 동적으로 로딩하는 것

런타임 동적 로딩 : 클래스를 로딩할 때가 아닌 코드를 실행하는 순간에 클래스를 로딩하는 것

 

Linking

클래스 파일을 사용하기 위해 검증 및 초기화를 하는 과정으로 세가지 단계를 거쳐 진행됩니다.

  1. Verify : 클래스 파일이 올바른지 검증(.class 파일 형식이 유효한지 체크)
  2. Prepare : 클래스와 인터페이스 등의 static 변수를 메모리 할당하고 기본값을 초기화
  3. Resolve : Symbolic Memory Reference를 메소드 영역의 Direct Reference(실제 주소)으로 변환 , 사용 환경에 따라 선택적으로 작동

 

Initialization

앞의 두 과정이 끝난 후 class 파일을 읽어 클래스와 인터페이스의 값들을 지정한 값으로 초기화하는 과정입니다.

 

Multi-Thread로 동작하기 때문에 동시성을 고려해야 합니다.

 

 

 

🚗 Execution Engine


실행 엔진은 클래스 로더를 통해 메모리에 할당된 클래스들을 기계어로 번역하여 명령어 단위로 실행시켜주며, 바이트 코드를 운영체제에 맞게 해석해주는 런타임 모듈입니다.

 

실행 엔진이 바이트 코드를 명령어 단위로 읽어 실행시켜주는 방식에는 두가지가 있습니다.

 

Interpreter

바이트 코드를 한 줄씩 읽어 네이티브 코드로 변환 후 실행시키는 방식으로 초창기에 사용되던 방식입니다.

중복되는 바이트 코드들에 대해서도 매번 컴파일을 하기 때문에 속도가 느립니다.

 

JIT (Just - In - Time) Compiler

인터프리터의 문제점을 해결하기 위해 도입된 방식으로

 

바이트 코드를 실제 실행하는 시점에 네이티브 코드로 변환하여 실행합니다.

 

JVM은 모든 코드를 JIT 컴파일러 방식을 사용하는 것이 아닌, 인터프리터 방식을 사용하다 반복되는 바이트 코드가 일정수준을 넘어가면 JIT 컴파일러 방식을 사용하는 혼합 방식을 사용합니다.

 

왜냐하면 바이트 코드를 네이티브 코드로 변환하는 것은 비용이 소모되기 때문에 한번 수행할 코드라면 네이티브 코드로 컴파일 하는 것보다 인터프리팅 하는 것이 더 유리하기 때문입니다.

 

이때 컴파일한 코드는 캐싱을 하게되므로 속도가 향상됩니다.

 

Garbage Collection (GC)

JVM의 Garbage Collecter가 메모리 누수를 방지하기 위해 주기적으로 Heap영역에서 더이상 참조되지 않는 불필요한 메모리(Garbage)를 청소하는 과정을 의미합니다.

 

GC 과정에서 중요한 두가지 개념이 있습니다.

  • Stop-the-world
  • Reachability

이에 대한 자세한 내용은 Heap 영역과 관계가 깊으므로 이곳에서 확인하시기 바랍니다.

 

 

💾 Runtime Data Area (메모리)


JVM이 프로그램을 실행하기 위해 운영체제(OS)로부터 할당받는 메모리 영역을 의미합니다.

런타임 시 클래스 데이터와 같은 메타 데이터와 실제 데이터가 저장되는 곳입니다.

 

Runtime Data Area는 5가지 영역으로 나누어지며 모든 쓰레드가 공유하는 영역 쓰레드별로 생성되는 영역으로 나눌 수 있습니다.

 

여기서 모든 쓰레드는 GC의 대상이 됩니다.

 

 

Method Area

클래스의 메타데이터가 저장되는 공간으로 클래스 파일의 바이트 코드를 보관하는 영역입니다.

JVM이 프로그램을 실행할 때 생성되어, JVM이 종료될 때 까지 유지됩니다.

 

주로 다음과 같은 정보들을 저장하고 있습니다.

  • 클래스 정보 : 클래스 이름, 인터페이스, 필드, 메소드 등의 정보
  • 메소드 코드 : 메소드의 바이트 코드
  • 상수 풀(Runtime Constant Pool) : 상수 값 저장, 상수 레퍼런스 참조에 사용되며 중복을 막아 줍니다.
  • static 변수 -> Permanant가  Metaspace로 바뀜에 따라 static 변수는 heap에서 관리하고 있습니다. 자세한 것은 이곳
  • JIT 컴파일러에서 변환된 기계어

메소드 영역은 여러 쓰레드가 동시 접근할 수 있기 때문에, JVM은 클래스 로딩 시 메소드 영역에 해당 클래스가 존재하는지 검사하여 존재한다면 새로 로딩 하지 않는 등의 동기화 기술을 통해 무결성을 보장하고 있습니다.

 

 

Heap Area

 

 

동적으로 할당되는 메모리 공간으로, 클래스의 인스턴스나 배열 등을 저장하고 공유하는 영역입니다.

이곳에 할당된 메모리는 GC에 의해 관리가 됩니다.

 

힙 영역은 3가지 구역으로 나누어질 수 있습니다.

  • Eden : 새롭게 생성된 객체가 할당되는 영역
  • Survivor : 최소 1번의 GC 이후 살아남은 객체가 존재하는 영역
  • Old : Young 영역에서 살아남은 객체가 복사되는 영역

자세한 내용은 GC와 관계가 깊으므로 이곳에서 확인하시기 바랍니다.

💡 Java 7 이전에는 Permanent 영역이 존재했지만 Java 8 이후부터로는 Metaspace 영역이 대체하였습니다.
Metaspace는 클래스 로더가 현재까지 로드한 클래스들의 메타데이터가 저장되는 공간인데 이는 JVM에 의해 관리되는 Heap이 아닌 OS 레벨에서 관리되는 Native 메모리 영역에 위치하게 됩니다.

추가적으로 Heap은 String pool을 가지고 있는데, 자세한 내용은 이 글 을 참고하세요.

 

Java Stack

자바의 메소드가 호출될 때 사용되는 메모리 공간으로, 호출된 메서드의 파라미터, 지역 변수, 리턴 값 및 연산 값 등 임시로 할당되었다가 메서드를 빠져 나갈 때 소멸되는 특성의 데이터들이 저장되는 영역입니다.

 

 

 

메서드 호출 시마다 스택에 각각의 스택 프레임이 생성되고, 수행이 끝나면 스택에서 해당 프레임을 제거하는데,

LIFO(Last In, First Out) 구조를 가지고 있어 가장 최근에 호출된 메서드가 가장 먼저 종료됩니다.

 

스택은 각 쓰레드별로 생성되어 다른 쓰레드에서는 접근할 수 없으므로 여러 쓰레드가 동시에 메서드 호출을 하더라도 서로의 스택에는 영향을 주지 않습니다.

 

Native Method Stack

자바 이외의 언어로 작성된 메소드의 정보가 저장되는 공간입니다.

 

자바 스택과 마찬가지로 쓰레드별로 존재하며 Java Native Inferface를 통해 호출되는 바이트 코드를 저장합니다.

 

PC Register

PC(Program Counter) 레지스터는 쓰레드 별로 하나씩 존재하며 현재 수행할 JVM의 명령어(JVM Instruction) 주소를 저장합니다.

 

JVM은 다음에 실행할 명령어를 찾기 위해서 현재 쓰레드의 PC Register 값을 참조하게 되는데, 쓰레드별로 각기 저장하고 있기 때문에 쓰레드별로 동시에 동작할 수 있게 됩니다. 

 

 

 

❔ 기타 궁금증


JDK , JRE , JVM의 차이점


 

  • JVM : 자바 프로그램을 컴파일하여 나온 바이트 코드를 실행시켜주는 가상머신
  • JRE : Java Runtime Environment의 약자로, 자바 실행 환경을 의미하며 JVM과 자바 프로그램을 실행시킬 때 필요한 라이브러리 API가 포함되어 있습니다.
  • JDK : Java Development Kit의 약자로, 자바를 이용해 개발하기 위해 사용되는 SDK를 의미합니다. 컴파일러, 디버거 등이 포함됩니다.

JDK > JRE > JVM 과 같은 식으로 포함되어 있다고 생각하면 쉽습니다. 

 

 

 

 

출처

http://net-informations.com/java/intro/jvm.htm

이것이 자바다 - 신용권의 JAVA프로그래밍 완전 정복

https://goodgid.github.io/Java-JVM/

https://jithub.tistory.com/40

https://blog.wanzargen.me/16

https://steady-coding.tistory.com/593

https://jiwonxdoori.tistory.com/33

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.