CH4. JVM 구조와 동작방식⭐

송쏭송·2024년 1월 26일

Java

목록 보기
4/8
post-thumbnail

이 글을 읽기전에 CH2. 메모장으로 Java 프로그램 개발해보기 를 보고 오는 것을 추천한다.
위 글에서 말했다 싶이 JVM클래스파일(.class) 을 실행시켜주는 역할을 한다.


JVM 동작원리

  1. Class Loader동적로딩 을 통해 클래스파일Runtime Data Area 에 올린다.

  2. Execution EngineRuntime Data Area 에 로딩된 바이트 코드를 실행한다.

CH2. 메모장으로 Java 프로그램 개발해보기 에서는 단지 JVMtest.class(클래스파일) 를 실행시켜준다고 했는데 이 과정을 좀 더 자세히 알아보자. 먼저, Class Loadertest.classRuntime Data Area 에 로딩한다. 그리고 나서 Execution EngineRuntime Data Area 에 로딩된 바이트 코드를 실행하는 것이다.

이때, tv.class(클래스파일)Runtime Data Area 에 로딩되지 않는다. 그 이유는, Test.java(소스파일) 에서 Tv 클래스 를 사용하지 않았기 때문이다. 만약, Test.java 에서 Tv 클래스 를 사용했다면, tv.classRuntime Data Area 에 올라갈것이다.

참고로, 잠시후 설명하겠지만 클래스파일이 저장되는 영역은 Runtime Data Area 의 여러 영역 중에서 Method Area 영역이다.


이렇게 JVM의 동작원리 에 대해 간단히 알아봤다.
이제, JVM의 구조 에 대해 알아보면서 위의 동작원리 를 완벽하게 이해해보자.


JVM 구조

JVM 은 크게 Class Loader, Runtime Data Area, Execution Engine 으로 구성된다.

위의 내용을 좀 더 세분화 하면 아래의 사진과 같다.

이처럼 JVM 은 아래와 같이 구성되어 있다.

Class Loader(클래스 로더)

Runtime Data Area(런타임 데이터 영역)

  • Method Area(메서드 영역)
  • Heap Area(힙 영역)
  • Stack Area(스택 영역)
  • PC Register(PC 레지스터)
  • Native Method Stack(네이티브 메서드 스택)

Execution Engine(실행 엔진)

  • Interpreter(인터프리터)
  • JIT 컴파일러(Just-in-Time 컴파일러)
  • Garbage collector(가비지 콜렉터)

Class Loader

Class Loader동적로딩 을 통해 클래스파일 들을 Runtime Data Area 에 올린다.

Execution EngineRuntime Data Area 중에서 Method Area 에 있는 바이트코드만을 실행할 수 있다. 자바 애플리케이션은 Execution Engine 이 선언부가 public static void main(String args[]) 인 메서드를 실행하면서 시작되는데, 이 메서드를 실행하면서 많은 클래스들이 사용될 것이다.
이때, 사용되는 클래스의 바이트코드가 즉, 클래스파일 이 아직 Method Area 에 없으면 이제서야 Class Loader 는 그 클래스파일을 찾아서 Method Area 에 로딩한다. 이것이 바로 동적으로 로딩하는 것이다.

사실, 위의 그림 처럼 Class Loader클래스파일Loading 하는것 뿐만 아니라 Linking, Initialization 과정도 수행한다.

Loading(로드)

  • 클래스파일 을 가져와서 Runtime Data Area(JVM 의 메모리) 에 올린다.

Linking(링크)

  • Verifying(검증) - 읽어들인 클래스가(실제로는 바이트코드를 읽어옴) JVM 명세에 명시된 대로 구성되어 있는지 검사한다.
  • preparing(준비) - 클래스가 필요로 하는 메모리를 할당한다.
  • Resolving(분석) - 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경한다.

Initialization(초기화)

  • 클래스 변수들을 적절한 값으로 초기화한다. ( static 필드들 초기화 등)

Runtime Data Area

Runtime Data Area(런타임 데이터 영역)OS 로부터 할당받은 JVM 의 메모리 영역으로 Java 애플리케이션 을 실행할 때 사용되는 데이터들을 적재하는 영역

Runtime Data Area 는 아래의 그림과 같이 같이 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack 로 나눌 수 있다.

위 사진 처럼 Method Area, Heap Area 는 모든 쓰레드(Thread) 가 공유하는 영역이고, 나머지 Stack Area, PC Register, Native Method Stack 은 각 쓰레드 마다 생성되는 개별 영역이다. 각 영역에 대해 알아보자.

Method Area

Method Area(메서드 영역)클래스파일 의 바이트코드가 로드되는 곳이다.

Method AreaClass AreaStatic Area 라고도 불린다. Method Area 에 저장되는 목록은 아래와 같다.

Type Information

  • 클래스와 인터페이스의 정보 저장

Runtime Constant Pool

  • Type의 상수 정보 저장
  • Type, Field, Method로 접근하기 위한 Reference 정보 저장
    즉, 어떤 메서드나 필드를 참조할 때, JVM은 런타임 상수 풀을 통해 메서드나 필드의 실제 메모리 상 주소를 참조하여 중복을 막는 역할

Field Information

  • 인스턴스 변수 정보 저장

Method Information

  • 모든 메서드 정보 저장

Class Variable

  • static 변수 정보 저장

Heap Area

Heap Area(힙 영역)new 키워드 즉, 동적으로 생성된 객체와 배열이 저장되는 영역

Heap Area 에 생성된 객체들은 다른 객체의 필드 또는 Stack Area 에 존재하는 참조 변수에 의해 참조된다. 즉, Heap Area 에는 객체 데이터만을 저장해 놓고 다른 객체의 필드나 Stack Area 의 참조변수에서 그 객체를 참조하는 것이다.

만약, 참조하는 변수나 필드가 없다면 의미 없는 객체가 되기 때문에 이것을 쓰레기로 취급하고 JVM 은 쓰레기 수집기인 Garbage Collector 를 실행시켜 쓰레기 객체를 Heap Area 에서 자동으로 제거된다

Stack Area

스택 영역은 int, long, boolean 등 기본 자료형을 생성할 때 저장하는 공간으로, 임시적으로 사용되는 변수나 정보들이 저장되는 영역이다.

메서드 호출 시마다 각각의 스택 프레임(그 메서드만을 위한 공간) 이 생성되고 스택 프레임 에서 메서드 안에서 사용되는 값들을 저장하고, 메서드의 매개변수나 지역변수, 리턴 값, 연산 시 일어나는 값들을 임시로 저장한다. 그리고 메서드 수행이 끝나면 각 스택 프레임 은 사라진다.

PC Register

PC Register(PC 레지스터) 는 현재 수행 중인 명령의 주소를 가진다

쓰레드 가 시작될 때, 생성되며 각 쓰레드 마다 하나씩 존재한다.

Native Method Stack

Native Method Stack(네이티브 메서드 스택)Java 외의 언어로 작성된 네이티브 코드를 위한 스택(Stack) 이다.

언어에 맞게 알맞는 스택이 생성된다. (C면 C 스택, C++이면 c++ 스택)


Execution Engine

Execution Engine(실행 엔진)Class Loader 를 통해 Runtime Data Area 에 적재된 바이트코드를 명령어 단위로 읽어서 실행

자바 바이트 코드는 기계가 바로 수행할 수 있는 언어가 아니라 JVM 이 이해할 수 있는 언어이다. 따라서, Execution Engine 은 이와 같은 바이트 코드를 기계가 수행할 수 있는 형태로 변경해준다.

이 과정에서 Execution Engine인터프리터JIT 컴파일러 를 혼합하여 사용한다.

Interpreter

Interpreter(인터프리터) 는 바이트코드 명령어를 하나씩 읽어서 해석하고 실행한다.

JVM 안에서 바이트코드는 기본적으로 인터프리터 방식으로 동작한다. 하나하나의 해석은 빠르지만, 전체적인 실행속도는 느리다. 그 이유는 같은 메서드가 여러번 호출이 된다면 매번 해석하고 수행해야하기 때문이다. 이 단점을 보완하기 위해 도입된 것이 JIT 컴파일러이다.

Jit 컴파일러

JIT 컴파일러(Just-In-Time Compiler) 는 바이트코드 전체를 컴파일하여 네이티브 코드로 변경하고 이후에는 해당 메서드를 더 이상 인터프리팅 하지 않고 네이티브코드로 직접 실행하는 방식

하나씩 인터프리팅 하여 실행하는것이 아니라 컴파일된 네이티브코드를 실행하는 것이기 때문에 전체적인 실행 속도는 인터프리팅 방식보다 빠르다.

하지만 바이트코드를 네이티브 코드로 변환하는 데에도 비용이 소요되므로, JVM 은 모든 코드를 JIT 컴파일 방식으로 실행하지 않고 인터프리팅 방식을 사용하다 일정 기준이 넘어가면 JIT 컴파일 방식으로 명령어를 실행하는 식으로 진행한다.

Garbage Collector

Garbage Collector(가비지 컬렉터)Heap Area 에서 더는 사용하지 않는 메모리를 자동으로 회수해 준다.

C언어 같은 경우 직접 개발자가 메모리를 해제해줘야 되지만, Java는 이 가비지 컬렉터 를 이용해 자동으로 메모리를 실시간 최적화 시켜준다. 따라서 개발자가 따로 메모리를 관리하지 않아도 되므로, 더욱 손쉽게 프로그래밍을 할 수 있도록 해준다.

일반적으로 자동으로 실행되지만, 가비지 컬렉터 가 실행되는 시간은 정해져 있지 않다.


References

JVM 내부 구조 & 메모리 영역 💯 총정리
[JAVA] JVM 동작원리 및 기본개념
[메모리] JVM의 메모리 사용 방식
[Java] 자바 JVM 내부 구조와 메모리 구조에 대하여
JAVA :: 자바의 메모리 구조 - 1. 메소드 영역(Method Area)
[JAVA] JVM Execution Engine (실행엔진)

0개의 댓글