Java는 클래스를 동적으로 읽는 프로그래밍 언어이다.
즉, 프로그램이 실행 중인 런타임
에 모든 코드가 JVM(Java Virtual Machine)에 연결된다.
동적으로 클래스를 로딩해주는 역할을 하는 것이 바로 클래스 로더(class loader)
이며,
운영체제로부터 할당받은 메모리 영역인 Runtime Data Area
에 컴파일된 .class
파일을 적재한다.
JVM의 Execution Engine
(실행 엔진)은 메모리에 배치된 Byte Code
들을 명령어 단위로 실행한다.
JVM은 프로그램 실행 중 다양한 런타임 데이터 영역을 사용한다.
동작을 시작하면 Heap Area
과 Method Area
가 생성되며 해당 영역들은 모든 스레드들이 공유한다.
또, 각 스레드가 시작될 때마다 PC Register
, Stack
, Native Method Stack
이 생성된다.
이렇게 생성된 3개의 메모리 영역은 각 스레드가 종료될 때 사라진다.
메서드 영역(Method Area)
또는 클래스 영역(Class Area)
은 클래스와 인터페이스의 구조가 저장되는 공간이다.
Metaspace
로 대체되었다.클래스의 구성 : 런타임 상수 풀, 필드와 메소드 그리고 코드
- 클래스는 멤버(member)로 속성을 표현하는 필드(field)와 기능을 표현하는 메소드(method)를 가진다.
- 또한, 생성된 객체의 필드를 초기화해주는 특별한 메소드인 생성자(constructor)를 가진다.
즉, 클래스 멤버 변수의 이름
, 데이터 타입
, 접근 제어자 정보
와 같은 각종 필드 정보들과
메서드 정보
, static 변수
, final class
등이 생성되는 영역이다.
Runtime Constant Pool
JVM의런타임 상수 풀
은 Java 프로그램에서 사용하는 상수를 저장하는 데 사용되는 데이터 구조이다.
프로그램이 상수를 사용하는 경우런타임 상수 풀 테이블
의상수 인덱스
를 사용하여 값을 검색할 수 있고,
상수가 필요할 때마다 조회할 필요가 없기 때문에 프로그램이 상수에 더 빠르게 액세스할 수 있다.
Heap 영역은 문자열
, 배열
및 기타 복잡한 데이터 구조 등 new키워드
로 생성된 인스턴스
들이 저장되는 공간이다.
힙 영역은 동적 메모리 영역
이므로 프로그램의 필요에 따라 크기를 조정할 수 있다.
JVM은 객체가 생성될 때 메모리를 할당하고, 더 이상 필요하지 않을 때 메모리 할당을 해제하여
힙 영역을 관리한다. 이는가비지 컬렉션(GC)
에 의해 주기적으로 관리된다.
힙 영역은 Java 프로그램의 모든 스레드에게 공유된다.
이는 모든 스레드가 힙 영역의 동일한 객체에 접근할 수 있으며, 동시에 수정할 수 있음을 의미한다.
스레드 간의 충돌을 방지하기 위해 JVM은 잠금 및 세마포어와 같은 동기화 메커니즘을 사용한다.
Heap 영역 구분
효율적인 GC를 위해 아래와 같이 나뉜다.
새로운 객체가 할당되는 영역으로, 수명이 짧은 객체를 위해 설계되었다.
Eden영역
은 객체가 최초로 할당되는 장소로, Eden 영역이 가득 차면 객체의 참조 여부를 파악 후
Live Object는Suvrvior영역
으로 넘기고, 참조가 사라진 Garbage Object는 GC에 의해 청소된다.
Young Generation에서 여러 라운드의 GC에 살아남은 객체는 Old Generation으로 승격된다.
이 영역에서 GC는 Young Generation 보다 덜 빈번하게 동작한다.
스택 영역은 메소드 프레임
과 로컬 변수
를 저장하기 위한 JVM 메모리의 일부이다. 메소드가 호출될 때마다 JVM은 로컬 변수 및 리턴 주소를 포함하여 메소드의 상태를 저장하기 위해 스택에 새 프레임을 작성한다.
스택은 후입선출(LIFO)
순서로 동작하며, 메서드가 실행을 완료하면 해당 프레임이 스택에서 제거되고 JVM이 이전 메소드의 프레임으로 돌아간다.
스택 영역은 인접한 메모리 위치
에 데이터를 저장하기 때문에 매우 빠르고 효율적으로 설계되어, JVM이 메모리를 빠르게 할당 및 해제할 수 있다. 스택 영역은 각 스레드가 자체 스택
을 가지고 있으며, 여러 스레드가 서로 간섭하지 않고 스택을 사용할 수 있기 때문에 스레드로부터 안전하다.
그러나 스택 영역의 크기는 제한
되어 있으며, 프로그램이 스택에 너무 많은 데이터를 저장하려고 하면 스택 오버플로 오류가 발생할 수 있다.
현재 스레드가 실행되는 부분의 주소와 명령
을 저장하고 있는 영역으로, PC(프로그램 카운터) 레지스터는 스레드의 현재 실행 상태를 추적하기 위해 사용된다.
각 스레드에는 고유한 PC 레지스터가 있고 이를 통해 여러 스레드가 서로의 실행 상태를 방해하지 않고 동시에 독립적으로 실행할 수 있다.
네이티브 메서드 스택은 C 또는 C++와 같은 Java 이외의 언어로 구현된 Java 코드
에서 호출하는 메서드에 대한 정보를 저장하는 JVM 메모리 영역이다.
Java 코드와 네이티브 코드의 상호 작용을 통해 순수 Java에서는 불가능했던 시스템 리소스 액세스 및 성능 최적화를 제공한다.