P2 -> P1로 리턴할 때 P2는 자기 자신의 local variable만 Pop을 하고 파리미터는 다음 제어권을 가진 P1이 Pop한다.
이 구조는 CPU, 기계어 아키텍처마다 다르다. 제어권을 넘기기 전에 파라미터를 Pop할 수도 있다.
JVM에서 Stack, Frame
1. Stack
그림 7 JVM Stack
JVM은 위 Call Stack과 같은 구조를 스레드 단위로 나누어 관리한다.
스레드가 생성되면 Stack도 같이 만들어진다.
스레드가 허용 Stack size를 넘기면 StackOverflowError 발생
Stack size는 동적으로 할당이 가능하다. 메모리가 부족하다면 OutOfMemoryError 발생
여기서 Frame은 위 Call Stack에서 local variable, return address, parameters를 포함하는 하나의 단위이다.
Frame은 위 Call Stack에서 설명한 요소를 가지는 것이 아니다. (이는 아래에 설명한다.)
Call Stack에 쌓인 요소들이 프로시저에 마다 색깔(파랑, 초록, 빨강)로 구별되는데, 이 하나의 단위를 Frame으로 이해하면 된다.
2. Frame
새로운 프레임은 메소드가 호출되었을 때 생성되고 메소드가 종료될 때 사라진다.
프레임은 Local variables, Operand stack, Reference to runtime constant pool 로 구성되어 있다.
2.1 Local Variables
Zero-based array of words로 구성되어 있다.
zero-based array : 0부터 시작하는 배열
word : 컴퓨터의 기본처리 단위 (32비트 컴퓨터 : 기본 처리 단위가 32비트이다.)
double, long을 제외한 나머지 primitve type, references, return address 모두 1칸의 공간을 차지한다.
double, long은 64bits 크기를 가지므로 2개의 공간을 차지한다.
byte, short, char, boolean 타입은 local variable 안에서 int로 변환이 된다. (이는 operand stack에서도 동일하게 일어난다.)
호출된 메소드가 static, non-static에 따라 frame 구성이 달라진다.
// 출처 : https://www.artima.com/insidejvm/ed2/jvm8.html
class Example3a {
public static int runClassMethod(int i, long l, float f,
double d, Object o, byte b) {
return 0;
}
public int runInstanceMethod(char c, double d, short s,
boolean b) {
return 0;
}
}
그림 8 local vairable (출처 : Inside JVM 2ed)
runClassMethod는 메소드 영역에 저장되어 있다.
객체 생성없이 클래스 이름으로 호출이 가능하다.
runInstanceMethod와 달리 0 인덱스에 'this'가 없다.
runInstanceMethod는 객체를 생성해야 존재한다
해당 instance data에 접근이 가능해야 하므로 'this'가 0에 위치한다.
2.2 Operand Stack
array of words로 구성되어 있다.
Operand(피연산자)는 연산의 대상을 나타내는 데이터 혹은 연산에 사용할 데이터를 지정(메모리 공간)을 뜻한다.
단, Stack이란 이름에서 알 수 있듯이 스택 구조로 동작한다. (local vairable와 달리 인덱스로 접근할 수 없다.)
값을 저장하는 작업 공간으로 활용된다.
// Main.java
class Main {
void add() {
int a = 100;
int b = 98;
int c = a+b;
}
}
2.3 Dynamic Linking (References to Runtime Constant Pool)
각 프레임은 run-time constant pool의 참조를 포함한다.
// Main.java
class Main {
public void test() {
Test t = new Test();
String name = "hello";
int big = 100000000;
t.add();
}
}
class Test {
public int add() {
int a = 1;
int b = 2;
return a+b;
}
}
// Main.class
class Main {
Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void test();
Code:
0: new #2 // class Test
3: dup
4: invokespecial #3 // Method Test."<init>":()V
7: astore_1
8: ldc #4 // String hello
10: astore_2
11: ldc #5 // int 100000000
13: istore_3
14: aload_1
15: invokevirtual #6 // Method Test.add:()I
18: pop
19: return
}