[Java] JVM의 메모리 구조 살펴보기

𝒄𝒉𝒂𝒏𝒎𝒊𝒏·2023년 4월 11일
0

Java

목록 보기
1/4
post-thumbnail

Java는 클래스를 동적으로 읽는 프로그래밍 언어이다.
즉, 프로그램이 실행 중인 런타임에 모든 코드가 JVM(Java Virtual Machine)에 연결된다.

동적으로 클래스를 로딩해주는 역할을 하는 것이 바로 클래스 로더(class loader)이며,
운영체제로부터 할당받은 메모리 영역인 Runtime Data Area에 컴파일된 .class파일을 적재한다.

JVM의 Execution Engine(실행 엔진)은 메모리에 배치된 Byte Code들을 명령어 단위로 실행한다.




✔️ JVM 메모리(Runtime Data Area)

JVM은 프로그램 실행 중 다양한 런타임 데이터 영역을 사용한다.
동작을 시작하면 Heap AreaMethod Area가 생성되며 해당 영역들은 모든 스레드들이 공유한다.

또, 각 스레드가 시작될 때마다 PC Register, Stack, Native Method Stack이 생성된다.
이렇게 생성된 3개의 메모리 영역은 각 스레드가 종료될 때 사라진다.

▶︎ 모든 스레드가 공유해서 사용(GC의 대상)

  • 메서드 영역(Method Area)
  • 힙 영역(Heap Area)

▶︎ 스레드(Thread) 마다 하나씩 생성

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



✔️ 스레드가 공유해서 사용하는 영역

▶︎ 메서드 영역(Method Area)

메서드 영역(Method Area) 또는 클래스 영역(Class Area)클래스와 인터페이스의 구조가 저장되는 공간이다.

📌 JDK 8 이후 해당 영역은 Metaspace로 대체되었다.

클래스의 구성 : 런타임 상수 풀, 필드와 메소드 그리고 코드
- 클래스는 멤버(member)로 속성을 표현하는 필드(field)와 기능을 표현하는 메소드(method)를 가진다.
- 또한, 생성된 객체의 필드를 초기화해주는 특별한 메소드인 생성자(constructor)를 가진다.

즉, 클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보와 같은 각종 필드 정보들과
메서드 정보, static 변수, final class 등이 생성되는 영역이다.

Runtime Constant Pool
JVM의 런타임 상수 풀은 Java 프로그램에서 사용하는 상수를 저장하는 데 사용되는 데이터 구조이다.
프로그램이 상수를 사용하는 경우 런타임 상수 풀 테이블상수 인덱스를 사용하여 값을 검색할 수 있고,
상수가 필요할 때마다 조회할 필요가 없기 때문에 프로그램이 상수에 더 빠르게 액세스할 수 있다.


▶︎ 힙 영역 (Heap Area)

Heap 영역은 문자열, 배열 및 기타 복잡한 데이터 구조 등 new키워드로 생성된 인스턴스들이 저장되는 공간이다.

힙 영역은 동적 메모리 영역이므로 프로그램의 필요에 따라 크기를 조정할 수 있다.
JVM은 객체가 생성될 때 메모리를 할당하고, 더 이상 필요하지 않을 때 메모리 할당을 해제하여
힙 영역을 관리한다. 이는가비지 컬렉션(GC)에 의해 주기적으로 관리된다.

힙 영역은 Java 프로그램의 모든 스레드에게 공유된다.
이는 모든 스레드가 힙 영역의 동일한 객체에 접근할 수 있으며, 동시에 수정할 수 있음을 의미한다.
스레드 간의 충돌을 방지하기 위해 JVM은 잠금 및 세마포어와 같은 동기화 메커니즘을 사용한다.

Heap 영역 구분
효율적인 GC를 위해 아래와 같이 나뉜다.

  • Young Generation
  • Old Generation

1. Young Generation

새로운 객체가 할당되는 영역으로, 수명이 짧은 객체를 위해 설계되었다.
Eden영역은 객체가 최초로 할당되는 장소로, Eden 영역이 가득 차면 객체의 참조 여부를 파악 후
Live Object는Suvrvior영역으로 넘기고, 참조가 사라진 Garbage Object는 GC에 의해 청소된다.

2. Old Generation

Young Generation에서 여러 라운드의 GC에 살아남은 객체는 Old Generation으로 승격된다.
이 영역에서 GC는 Young Generation 보다 덜 빈번하게 동작한다.



✔️ 스레드 마다 하나씩 생성하는 영역

▶︎ 스택 영역 (Stack Area)

스택 영역은 메소드 프레임로컬 변수를 저장하기 위한 JVM 메모리의 일부이다. 메소드가 호출될 때마다 JVM은 로컬 변수 및 리턴 주소를 포함하여 메소드의 상태를 저장하기 위해 스택에 새 프레임을 작성한다.

스택은 후입선출(LIFO) 순서로 동작하며, 메서드가 실행을 완료하면 해당 프레임이 스택에서 제거되고 JVM이 이전 메소드의 프레임으로 돌아간다.

스택 영역은 인접한 메모리 위치에 데이터를 저장하기 때문에 매우 빠르고 효율적으로 설계되어, JVM이 메모리를 빠르게 할당 및 해제할 수 있다. 스택 영역은 각 스레드가 자체 스택을 가지고 있으며, 여러 스레드가 서로 간섭하지 않고 스택을 사용할 수 있기 때문에 스레드로부터 안전하다.

그러나 스택 영역의 크기는 제한되어 있으며, 프로그램이 스택에 너무 많은 데이터를 저장하려고 하면 스택 오버플로 오류가 발생할 수 있다.


▶︎ PC 레지스터 (PC Register)

현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역으로, PC(프로그램 카운터) 레지스터는 스레드의 현재 실행 상태를 추적하기 위해 사용된다.

각 스레드에는 고유한 PC 레지스터가 있고 이를 통해 여러 스레드가 서로의 실행 상태를 방해하지 않고 동시에 독립적으로 실행할 수 있다.


▶︎ 네이티브 메서드 스택 (Native Method Stack)

네이티브 메서드 스택은 C 또는 C++와 같은 Java 이외의 언어로 구현된 Java 코드에서 호출하는 메서드에 대한 정보를 저장하는 JVM 메모리 영역이다.

Java 코드와 네이티브 코드의 상호 작용을 통해 순수 Java에서는 불가능했던 시스템 리소스 액세스 및 성능 최적화를 제공한다.

profile
𝑶𝒏𝒆 𝒅𝒂𝒚 𝒐𝒓 𝒅𝒂𝒚 𝒐𝒏𝒆.

0개의 댓글