■ 정의 : Runtime Data Areas는 Process로서의 JVM이 프로그램을 수행하기 위해 OS로 부터 할당받는 메모리 영역
Runtime Data Areas의 5개의 영역
PC Registers
Method Area
Heap
Native Method Stacks
Java Virtual Machine Stack
- PC Registers
- 프로그램의 실행은 CPU에서 명령어, 즉 인스트럭션(Instruction)을 수행하는 과정으로 이루어진다. CPU는 이러한 Instruction을 수행하는 동안 필요한 정보를 레지스터(Register) 라고 하는 CPU내의 기억장치를 사용한다.
1 + 2 1 과 2 처럼 명령실행에 사용되는 데이터를 Operand 라고 한다. 그리고 결과인 3 이라는 Operand 도 메모리로 전달하기 전에 CPU어딘가에 잠시 머무른다. 이 공간이 레지스터.
- Runtime Data Area의 메모리 영역인 PC Register는 이것과는 다르다. Java는 Register-Base로 구동되는 방식이 아니라, Stack-Base방식으로 작동한다. JVM은 CPU에 직접 Instruction을 수행하지 않고 Stack에서 Operand를 뽑아내어 이를 별도의 메모리 공간에 저장하는 방식을 취하고 있다. 이러한 메모리 공간을 PC Registers 라고 한다.
- Java는 플랫폼에 있어서는 독립적이다(CPU아키텍처 같은 Instruction Set) 하지만 JVM 도 OS나 CPU의 입장에서 보면 머신에서 동작하는 하나의 프로세스에 지나지 않기 때문에 머신의 리소스를 사용해야 하는 것도 너무도 당연, 그렇기 때문에 Java도 현재 작업하는 내용을 CPU에 Instruction으로 제공해야 하며, 이를 위한 버퍼공간으로서 PC Registers 라는 메모리 영역을 생성한것
- PC Registers는 각 Thread마다 하나씩 존재하며 Thread가 시작할 때 생성된다. 만약 Thread가 Java Method를 수행하고 있으면 이 PC Registers에는 현재 수행중인 Java Virtual Machine Instruction의 주소를 가지고 있게 된다.
- Java Virtual Machine Stack
- Java Virtual Machine Stack 은 Thread의 수행정보를 기록하는 Frame을 저장하는 메모리 영역이다.
- Thread마다 하나씩 존재하며 Thread가 시작할 때 생성된다. Java Virtual Machine Stack에 있는 모든 데이터는 각 Thread가 소유하며, 다른 Thread는 접근이 불가능하다. 그렇기 때문에 Java Virtual Machine Stacks에서는 동기화에 대한 이슈가 발생하지 않는다.
대표적인 예로 로컬변수(Local Variable)를 들 수 있다.
- Java Virtual Machine Stack은 Stack Frame들로 구성이 되는데 JVM은 Stack Frame을 Java Virtual Machine Stacks에 넣고(Push) 빼는(Pop or Pull) 작업만 수행한다.
Stack Trace, Stack Dump를 얻어내어 분석을 하는것도 이 곳이다.
- 여러 Stack Frame중 현재 수행하고 있는 Method 의 정보를 저장하는 것을 Current Frame이라고 한다. 그리고 현재 수행하고 있는 Method의 Class를 Current Class라고 한다.
JVM이 현재 Method를 수행하고 있다면 Current Frame을 통해 Current Class와 같은 Current 정보를 계속해서 주시하게 된다. 이 Stack Frame에는 Method의 파라메터 변수, 지역변수, 연산의 결과 등과 같은 데이터들을 저장한다.
- Thread가 Java Method를 하나 수행하게 되면, JVM은 Stack Frame을 하나 생성하여 Java Virtual Machine Stacks에 Push한다. 그렇게 새로 들어간 Stack Frame은 Current Frame이 된다. 만약 Method가 비정상 종료하게 되면 Exception 처리를 하는 작업을 수행한 후 Java Virtual Machine Stacks에서 사라지게 된다.
Stack Frame
Stack Frame은 Thread가 수행하고 있는 Application을 Method 단위로 기록하는 곳,
Local Variable Section, Operand Stack, Frame Data의 세부분으로 구성,
Stack Frame은 Method를 실행하게 되면 Class의 메타정보를 이용하여 적절한 크기로 생성되는데, 그 크기는 Compile Time에 결정된다.
- LocalVariable Section
Method의 Paramether Variable과 Local Variable 들을 저장한다. 0부터 시작하는 인덱스를 가진 Array들로 구성되어 있고, 이 Array의 인덱스를 통해 데이터에 접근,
Method 파라메터는 선언된 순서로 인덱스가 할당되며, 로컬변수는 Compiler가 알아서 인덱스를 할당한다. 선언만 해놓고 사용하지 않는 로컬변수는 인덱스를 할당하지 않을 수도 있다. 인덱스 할당은 Local Variable Section에 저장공간을 마련한다는 것을 의미한다.
원시타입(primitive Type) 변수와 객체가 들어갈때 Local Variable Section에 저장되는 값은 다르다.
원시타입은 값 그대로 Local Variable Section에 들어가지만, 객체는 Reference형태로 참조가 된다. Java에서 모든 객체가 저장되는 곳은 바로 Heap이라는 메모리 영역이다.
객체정보는 Java Virtual Machine Stack 에 직접 저장되는 것이 아니라 해당 객체가 존재하고 있는 Heap의 위치를 말해주는 Reference를 저장한다. 그리고 그 Reference를 통해 실제 객체가 저장되어 있는 Heap을 찾아가는 것이다.
0번 인덱스의 Reference는 Heap에 있는 Class의 Instance데이터 참조를 위한것, Local Method가 아닌 Class Method, static으로 선언한 Method의 경우 Reference정보가 존재하지 않는다. 이것은 Class Variable과 마찬가지로 Instance에 속한것이 아니라, Class 자체에 속해있는 것이다.
- Operand Stack
JVM의 작업공간, JVM이 프로그램을 수행하면서 연산을 위해 사용되는 데이터 및 그 결과를 Operand Stack에 집어넣고 처리를 한다.
class JvmInternal{
public void operandStack(){
int a, b , c;
a = 5;
b = 6;
c = a + b;
}
}
위와 같은 Java 파일을 컴파일 한뒤 'javap -c' 를 사용하여 Method의 Bytecode를 추출한 결과는 아래와 같다
Compiled from "JvmInternal.java"
class JvmInternal {
JvmInternal();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void operandStack();
Code:
0: iconst_5
1: istore_1
2: bipush 6
4: istore_2
5: iload_1
6: iload_2
7: iadd
8: istore_3
9: return
}
iconst_5는 상수5를 push 하라는 것을 의미하는 Bytecode이다.
istore_1은 Local Variable Section의 1번 인덱스에 값을 저장하는 것을 의미한다.
istore_1 | istore_2 | iload_1 | iload_2 | iadd | istore_3 | |||||||||||
Operand | Stack | 6 | ||||||||||||||
5 | 5 | 11 | ||||||||||||||
Local | int c | 3 | 11 | |||||||||||||
Variable | int b | 2 | 6 | 6 | 6 | 6 | 6 | |||||||||
Section | int a | 1 | 5 | 5 | 5 | 5 | 5 | 5 | ||||||||
hidden this | ref | 0 | ref | ref | ref | ref | ref | ref |
Operand Stack Local Variable Section에서의 연산과정
-Frame Data
Stack Frame을 구성하고 있는 또 하나의 영역, 이곳에는 Constant Pool Resolution 정보와 Method 가 정상 종료했을 때의 정보들, 그리고 비정상 정료를 했을 시에 발생하는 Exception 관련 정보들을 저장하고 있다.
Resolution => Java는 모든 참조정보를 Symbolic Reference로 가지고 있는데, 이 Symbolic Reference는 JVM에서 실제로 접근 할 수 있는 실질적인 Direct Reference로 변경이 되는데 이러한 것을 Resolution이라고 힌다.
Class의 모든 Symbolic Reference는 Method Area의 Constant Pool이라는 곳에 저장되어 있기 때문에 Resolution을 Constant Pool Resolution이라고 부르는 것이다.
Frame Data에 저장된 Constant Pool Resolution 정보는 , 관련 Constant Pool의 Pointer 정보이다. JVM은 이 Pointer를 이용하여 필요할 때 마다 Constant Pool을 찾아간다.
보통 상수를 가져올때 Constant Pool의 Entry 정보를 참조하기도 하지만 다른 Class를 참조하거나, Method를 수행하거나 아니면 특정 변수들을 접근할 때에도 Constant Pool을 참조해야 한다. Java의 모든 Reference는 Symbolic Reference이기 때문에 Class나 Method, 그리고 변수나 상수에 접근할 때에도 이러한 Resolution이 수행된다. 또한 특정 Object가 특정 Class나 Interface에 의존관계가 있는지 확인하기 위해서도 Constant Pool의 Entry를 참조한다.
Frame Data에는 자신을 호출한 Stack Frame의 Instruction Pointer가 들어가 있다. Method가 종료되면 JVM은 이 정보를 PC Register에 설정하고 Stack Frame을 빠져 나간다. 만약 이 Method가 반환값이 있다면 이 반환 값을 다음 번 Current Frame, 즉 자신을 호출한 Method의 Stack Frame의 Operand Stack에 Push 하는 작업도 병행한다. 또한 Exception Handling 정보 또한 Frame Data영역에 저장하고 있다.
댓글 없음:
댓글 쓰기