jacketList

[JAVA]JVM 메모리 구조 본문

Java

[JAVA]JVM 메모리 구조

ukkkk7 2023. 12. 3. 15:24
728x90
반응형

 

 

JVM이란?

자바 가상 머신 JVM(Java Virtual Machine)은 자바와 운영체제 사이에서 중개자 역할을 하며, 자바가 운영체제에 구애 받지 않고 다른 프로그램을 실행할 수 있도록 도와준다.

자바 코드를 컴파일하여 .class 바이트 코드로 만들면 이 코드가 자바 가상 머신 환경에서 실행됩니다.

 

※.class 파일은 바이트 코드라고 하는데 사람이 쓰는 자바 코드에서 컴퓨터가 읽는 기계어로의 중간 단계라고 생각하면 된다.

 

 

 

JVM의 동작방식

  1. 자바 프로그램을 실행하면 JVM은 OS(운영체제)로부터 메모리를 할당받는다.
  2. 자바 컴파일러(javac)가 자바 소스코드(.java)를 자바 바이트 코드(.class)로 컴파일 한다.
  3. class Loader는 동적 로딩을 통해 필요한 클래스들을 로딩 및 링크하여 Runtime Data Area(실질적인 메모리를 할당 받아 관리하는 영역)에 올린다.
  4. Runtime Data Area에 로딩 된 바이트 코드는 Execution Engine을 통해 해석된다.
  5. 이 과정에서 Execution Engine에 의해 Garbage Collector의 작동과 Thread 동기화가 이루어진다.

 

 

JVM의 구조

 

클래스 로더(Class Loader)

 

클래스 로더는 JVM내로 클래스 파일을 동적으로 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.

즉, 로드된 바이트 코드(.class)들을 엮어서 JVM의 메모리 영역인 Runtime Data Areas에 배치한다.

 

 

클래스 파일의 로딩 순서는 다음과 같이 3단계로 구성된다(Loading -> Linking -> Initialization)

  • Loading(로드) : 클래스 파일을 가져와서 JVM의 메모리에 로드한다.
  • Linking(링크) : 클래스 파일을 사용하기 위해 검증하는 과정이다. 3단계의 검증 과정을 거친다
    • Verifying(검증) : 읽어들인 클래스가 JVM명세에 명시된 대로 구성되어 있는지 검사한다.
    • Preparing(준비) : 클래스가 필요로 하는 메모리를 할당한다.
    • Resolving(분석) : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경한다. -> 실제 객체의 주소를 참조하게 된다.
  • Initialization(초기화) : 클래스 변수들을 적절한 값으로 초기화한다. (static 필드들을 설정된 값으로 초기화 등)

 

실행 엔진(Execution Engine)

실행 엔진은 클래스 로더를 통해 런타임 데이터 영역에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다.

 

자바 바이트 코드(.class)는 기계가 바로 수행할 수 있는 언어보다는 가상머신이 이해할 수 있는 중간 레벨로 컴파일 된 코드이다. 그래서 실행 엔진은 이와 같은 바이트 코드를 실제로 JVM내부에서 기계가 실행할 수 있는 형태로 변경해준다.

 

이 과정에서 JIT컴파일러인터프리터 두 가지 방식을 혼합하여 바이트 코드를 실행한다.

 

인터프리터(Interpreter)

  • 바이트 코드 명령어를 하나씩 읽고 실행
  • 같은 메소드라도 여러번 호출이 된다면 매번 해석하고 수행해야 되서 전체적인 속도는 느리다.

JIT 컴파일러(Just - In - Time - Compiler) : 

  • Interpreter의 단점을 보완하기 위해 도입된 방식으로 반복되는 코드를 발견하여 바이트 코드 전체를 컴파일하여 Native Code로 변경하고 해당 메소드를 캐싱해 두었다가 네이티브 코드로 직접 실행하는 방식이다.
  • 컴파일 된 네이티브 코드를 실행하기 때문에 인터프리팅 방식보다 실행 속도가 빠르다.
  • 바이트 코드를 Native Code로 변환하는 데에도 비용이 들기 때문에 인터프리터 방식과 혼합해서 사용한다.

※ 네이티브 코드(Native Code) : Java에서 부모가 되는 C언어나, C++, 어셈블리어로 구성된 코드를 의미

 

 

 

가비지 컬렉터(Garbage Collector, GC)

 

자바 가상 머신은 가비지 컬렉터(Garbage Collector)를 이용하여 Heap 메모리 영역에서 더는 사용하지 않는 메모리를 자동 회수해 준다.

 

Java는 이 가비지 컬렉터를 이용해 자동으로 메모리를 실시간 최적화 시켜준다. 일반적으로 자동 실행되지만 GC가 실행되는 시간은 정해져 있지 않다.

GC역할을 수행하는 스레드를 제외한 나머지 모든 스레드들은 일시정지 상태가 된다.

 

 

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

 

 

런타임 데이터 영역은 JVM메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다.

 

런타임 데이터 영역은 위의 그림과 같이 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack으로 나눌 수 있다.

 

Method Area, Heap Area는 모든 쓰레드가 공유하는 영역이고, 나머지 Stack Area, PC Register, Native Method Stack은 각 쓰레드마다 생성되는 개별 영역이다.

 

 

 

메소드 영역(Method Area)

메소드 영역은 JVM이 시작될 때 생성되는 공간으로 바이트 코드(.class)를 처음 메모리 공간에 올릴 때 초기화되는 대상을 저장하기 위한 메모리 공간이다.

JVM이 동작하고 클래스가 로드될 때 적재되서 프로그램이 종료될 때까지 저장된다.

클래스 수준의 정보(클래스 이름, 부모 클래스 이름, 메소드, 변수)를 저장한다. 다시말해 메소드 영역은 정적 필드와 클래스 구조만을 갖고 있다.

 

 

힙 영역(Heap Area)

힙 영역은 메소드 영역과 함께 모든 쓰레드가 공유하며, JVM이 관리하는 프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 영역이다.

즉, new 연산자로 생성되는 클래스와 인스턴스 변수, 배열 타입 등 Reference Type이 저장되는 곳이다.

 

 

주기적으로 GC가 제거하는 영역이기 때문에 Heap Area는 효율적인 GC를 위해 위와 같이 크게 3가지 영역으로 나뉜다.

 

Young Generation 영역

자바 객체가 생성되자마자 저장되고, 생긴지 얼마 안되는 객체가 저장되는 공간이다. 

객체가 최초로 생성되면 Eden영역에 할당된다. 그리고 이 영역에 데이터가 어느정도 쌓이게 되면 참조 정도에 따라 Servivor의 빈 공간으로 이동되거나 회수된다.

 

Young Generation영역이 차게 되면 참조 정도에 따라 Old영역으로 이동하거나 회수된다. Young Generation과 Tenured Generation에서의 GC를 Minor GC라 하고 한다. Old영역에 할당된 메모리가 허용치를 넘게 되면, Old 영역에 있는 모든 객체들을 검사하여 참조되지 않는 객체들을 한꺼번에 삭제하는 GC가 실행된다. 'stop-the-world' 라 부르며 GC를 실행하는 쓰레드를 제외한 모든 쓰레드는 작업을 멈추게 되기 때문에 시간이 오래 걸린다. 이렇게 Old영역 메모리를 회수하는 GC를 Major GC라고 한다.

 

 

스택 영역(Stack Area)

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

 

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

 

PC 레지스터

Thread가 생성될 때마다 생성되는 영역으로 프로그램 카운터, 즉 현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역이다.

 

네이티브 메소드 스택

자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 네이티브 코드를 실행할 때 사용되는 메모리 영역으로 일반적인 C스택을 사용한다.

보통 C/C++ 등의 코드를 수행하기 위한 스택을 말할며 JNI 자바 컴파일러에 의해 변환된 자바 바이트 코드를 읽고 해석하는 역할을 하는 것이 자바 인터프리터 이다.

 

 

JVM의 구조는 양이 많고 어렵기 때문에 일단 겉핥기 식으로 정리하고, 추후 각각의 영역에 대해 더 자세히 알아볼 예정이다....

 

 

 

 

References

https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8

https://velog.io/@dyunge_100/JAVA-JVM%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0-%EB%B0%8F-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC

https://coding-factory.tistory.com/828

 

 

 

728x90
반응형