[JAVA] 자바 메모리 구조 - 2편


스택 영역(Stack Area)

  • 스택 영역에는 지역변수와 매개변수가 저장된다.

  • 참조변수에 저장되는 메모리주소는 스택영역에 저장되지만, 그 주소가 가리키는 메모리는 모두 힙 영역에 저장된다.

  • 지역변수 : 로컬변수(local variable)

    • 메소드 내에서 선언된 변수
  • 매개변수 : 파라미터(parameter)

    • 메소드에 argument(인자)로 넘겨주는 값
  • 로컬변수와 매개변수의 특징은 이 아이들이 선언된 그 블록 안에서만 유효한 변수들이라는 점, 이 변수들이 스택 영역에 저장됨.

  • 쉽게 스택 영역에는 프로그램의 실행 과정에서 ‘임시로 할당’되고, 그게 끝나면 바로 소멸되는 것들이 저장된다.

  •  메소드가 호출될 때마다 그 메소드의 로컬 변수를 준비하고, 메소드 호출이 끝나면 그 메소드를 위해 준비했던 모든 변수가 스택에서 제거된다.

// 스택영역
public class StackMemoryTest {
  public static void m1(int a) {
    m2(++a);
    System.out.printf("m1():%d\n", a);
  }
  
  public static void m2(int a) {
    m3(++a);
    System.out.printf("m2():%d\n", a);
  }
  
  public static void m3(int a) {
    ++a;
    System.out.printf("m3():%d\n", a);
  }
  
  public static void main(String[] args) {
    int a = 20;
    m1(a);
    System.out.printf("main():%d\n", a);
  }
}

  • 결과

    • m3(): 23
      m2(): 22
      m1(): 21
      main(): 20
  • 이런 결과가 나오는 이유는, 처음에 들어간 것이 나중에 나오는 스택 구조의 특성 때문이다.

구조 : FILO(First In Last Out, 선입 후출)

  • 들어갈 때는 처음에 들어간 요소 위에 다른 요소가 쌓인다.

  • 나올 때는 스택 최상위 요소 부터 나온다.


결과 분석

  • 이렇게 지역변수의 값은 해당 메소드가 실행되면, 그 메소드의 스택번지에 값이 저장된다. 그리고 해당 메소드가 모두 실행되고나면, 스택에서 해당 메소드의 스택번지가 제거되는 구조이다.


힙 영역(Heap Area)

  • 힙 영역에는 흔히 코드에서 ’new’명령을 통해 생성된 인스턴스 변수가 놓인다. 어떤 메소드인지는 상관이 없다. new 명령으로 만드는 메모리는 모조리 힙 영역에 보관된다.

  • 힙 영역에 보관되는 메모리는 메소드 호출이 끝나도 사라지지 않고 유지된다.

  • 언제까지 존재할까? : 주소를 잃어버려 가비지가 되어 가비지 컬렉터에 의해서 지워질 때까지. 아니면 JVM이 종료될때까지.

  • 8가지 원시타입(byte, short, int, long, float, double, char, boolean)을 제외한 그외의 타입으로 정의된 변수들은  모조리 레퍼런스 변수, 즉 참조변수이다.

  • 이런 참조변수들은 실행될 때마다 많은 데이터들을 스택메모리 영역에 뒀다 뺐다 하는게 매우 비효율적이므로, 힙 영역에 그 내용(진짜 값)이 저장되고, 스택 메모리에는 간단하게 그 주소만 저장이 되는 것이다.

  • 그리고 힙 영역에는 실제 그 변수가 가리키고 있는 값들이 저장되어 있다.

// 힙 영역
public class HeapMemoryTest {
 
  public static int[] m1(int a) {
    int[] arr = m2(a + 1);
    arr[2] = a;
    return arr;
  }
  
  public static int[] m2(int a) {
    int[] arr = m3(a + 1);
    arr[1] = a;
    return arr;
  }
  
  public static int[] m3(int a) {
    int[] arr = new int[3];
    arr[0] = a;
    return arr;
  }
  
  
  public static void main(String[] args) {
    int[] arr = m1(100);
    for (int i = 0; i < arr.length; i++) {
      System.out.printf("%d=%d\n", i, arr[i]);
    }
  }
}
  • 결과

    • 0=102
      1=101
      2=100

결과 분석

  • 인스턴스를 별도의 힙 영역에 할당하는 이유는 인스턴스의 소멸방법과 소멸시점이  지역변수(스택영역에 할당되는 애들)와는 다르기 때문

  • 굳이 메모리 영역을 몇 개로 나눠서 관리하는 이유가, 일상생활에서도 용도에 따라 물건을 다른 장소에 관리하는게  편한것과 같은 맥락이라고 보면 된다.


간단 정리

  • 스택 영역의 지역변수들은 메소드가 호출되고 끝이 나는 프로그램의 실행 흐름에 관여하는 것들

  • 힙 영역의 인스턴스들은지역변수가 참조하고 있는 실제의 값들을 가지고 있다.


Reference