[Java] JVM 구조와 메모리 사용영역, Java 쓰레드와 메모리 구조
목차
배경
Java의 동작원리와 문법을 제대로 깊게 공부해본 적이 없어 이번 기회에 다시 학습하는 중인데 그 중 자바 실행 환경인 JVM과 기본적인 메모리 구조는 공유해두면 많은 도움이 될 것 같아 블로그에 별도로 기록해두었다.
JVM(Java Virtual Machine)
자바 프로그램 실행환경을 만들어 주는 소프트웨어
자바 코드(.java)를 컴파일하여 .class 바이트 코드로 만들면, 이 코드를 JVM 환경에서 실행
JVM 구조
메모리 주소상 위치 : Low address(0x0000000) ~ High address(0xFFFFFFFF)
Heap 영역은 낮은(Low) 메모리 주소에서 높은(High) 메모리 주소로 할당받으며, Stack 영역은 그 반대이다.
JVM Runtime Data Area
java 명령어로 JVM(java virtual machine)을 구동하며, JVM은 운영체제에서 할당받은 메모리 영역을 다음과 같이 구분하여 사용하며 그 구조를 나타내면 위 이미지와 같다.
1. 메소드 영역(method area)
- JVM이 실행되면서 생기는 공간
- 프로그램을 실행하는 자바 코드(Class 정보, 전역 변수, 상수 필드, static 필드, 메소드 코드, 생성자 코드)를 포함
- 바이트코드 파일(.class)의 내용이 저장되는 영역
- 모든 Thread에서 정보가 공유된다.
2. 힙 영역(heap area)
- new 연산자로 객체를 생성하거나 Array를 동적으로 생성하면서 데이터가 저장되는 공간
- 객체, 배열 등을 포함하여 참조 타입 변수의 실제 데이터가 저장되는 영역
- Garbage Collector가 처리하지 않는 한 Heap에 저장된 데이터는 소멸되지 않는다.
- 스택 영역에서 생성되는 참조 변수는 객체의 주소인 힙 영역의 메모리 주소를 참조한다.
- 힙 영역은 새로운 데이터가 추가될수록 더 높은(High) 메모리 주소를 할당받는다(스택 영역의 메모리 할당 규칙과 정 반대이다)
- 스택 영역과 힙 영역은 공유 라이브러리 영역을 가운데에 두고 서로 마주보기 때문에 메모리 공간을 알뜰하게 활용할 수 있다.
- 모든 Thread에서 정보가 공유된다.
3. 스택 영역(stack area)
- 지역 변수, 매개변수 등과 같이 잠시 사용 되고 필요가 없어지는 데이터가 저장되는 영역
- 메서드가 호출될때마다 메서드 프레임(method frame)이 생성되고 저장되는 영역
- 메소드 호출이 끝나면 메서드 프레임은 자동 제거된다.
- 프레임 내부에 로컬 변수 스택(local variable stack)이 존재
- 기본 타입 변수와 참조 타입 변수가 생성되고 제거되는 영역이다.
- 스택 영역은 항상 kernel의 반대방향으로 자라기 때문에 영원히 kernel을 만나지 않게 된다. 따라서, 스택이 아무리 커져도 커널은 건드리지 않는다.
- Thread 마다 하나씩 존재한다.
4. PC Register
- Thread가 생성되면서 생기는 공간
- Thread가 어느 명령어를 처리하고 있는지 그 주소를 등록한다.
- JVM이 실행되고 있는 현재 위치를 저장하는 역할
- Thread 마다 하나씩 존재한다.
5. Native Method Stack
- Java가 아닌 다른 언어(C, C++)로 구성된 메소드 실행이 필요할때 사용되는 공간
- Thread 마다 하나씩 존재한다.
Thread 구조
Thread는 한 Process 내에서 Heap, Method Area 영역을 공유하며 독립적인 Stack, PC Register, Native Method Stack 영역을 갖는다. 한 프로세스 내에서 동작되는 여러 Thread는 프로세스 내의 주소 공간이나 자원(Method, Heap Area)을 공유하며 독립적인 작업을 수행하기 위한 Stack과 PC Register, Native Method Stack 영역을 갖는다.
Thread와 Memory 구조
한 Process 내에 여러개의 Thread가 존재하고 각 Thread 영역 내부에 독립적인 Stack area가 존재, 다시 각 Stack area 내부에 여러개의 method frame이 존재한다.
Stack을 Thread 마다 독립적으로 할당하는 이유
스택은 한 번 사용하고 나면 더이상 사용하지 않는 변수 즉, 함수 호출시 전달되는 매개변수나 지역변수 등을 저장한다. 스택 영역이 독립적이라는 말은 독립적인 함수 호출이 가능하다는 의미이며, 이는 한 프로세스 내에서 독립적인 실행 흐름을 가능케한다. 따라서 Thread의 독립적인 실행 흐름을 위한 최소 조건으로 독립적인 Stack Area를 할당한다.
PC Register를 Thread 마다 독립적으로 할당하는 이유
이 이유를 이해하기 위해서는 두가지 개념을 알고있어야 한다. 첫번째는 Thread는 CPU를 할당받았다가 Scheduler에 의해 다시 선점(pre-emption)당한다는 것이고 두번째는 PC Register 영역은 Thread가 어느 명령어를 처리하고있는지 즉, 현재 JVM이 실행되고 있는 위치를 저장한다는 것이다.
OS(운영체제)의 Scheduler는 어떤 프로세스가 CPU를 할당받을지 정하는데, 이때 Stack Area의 한 Thread에게만 CPU를 할당하여 동작하다가 스케쥴링에 의해 CPU를 다른 Thread에게 할당하고 기존에 할당받았던 Thread가 대기(Waiting) 상태로 들어간다면, 그리고 후에 다시 CPU를 할당할때 대기중이던 Thread가 어느 지점까지 동작하고 있었는지를 알고 있어야 한다. 이 실행되고 있던 어느지점(= 독립적인 실행 흐름) 또한 Thread 마다 할당되기 때문에 PC Register 영역도 Thread마다 독립적으로 할당한다.
출처