메모리 구조

출처 : baeldung

메모리는 Method Area - Call Stack - Heap 영역으로 구분된다. 각각의 영역이 어떤 역할을 수행하는지 알아보자.

  • Method Area

    • 클래스 파일의 바이트 코드가 할당되는 영역이다. class 파일의 자바 애플리케이션 코드가 JVM에 의해 기계어로 변환되어 실행이 되는데, 이 때 변환된 기계어가 바이트 코드이다.
    • static 으로 선언된 클래스가 여기에 할당된다.
  • Call Stack

    • 지역 변수와 매개변수가 임시로 할당되는 영역이다.
    • 메서드가 호출되면, 수행에 필요한만큼의 메모리를 스택에 할당
    • 메서드가 수행을 마치고 나면 사용했던 메모리를 반환, 스택에서 제거한다.
      아까 지역변수와 매개변수가 임시로 할당된다고 이야기한 이유가 여기에 있다. 변수들을 호출하는 메서드가 사용되고 나면 해당 메서드의 모든 변수를 삭제하기 때문이다. 불필요한 메모리를 삭제하는 GC(Garbage Collector)가 작동되는 것으로 보인다.
    • 호출 스택의 제일 위에 있는 메서드가 현재 실행중인 메서드이며, 바로 아래에 있는 메서드가 현재의 메서드를 호출한 메서드이다. 일반적으로 main()가 실행되면서 애플리케이션이 실행되므로 가장 먼저 호출된 main() 이 Call Stack의 가장 아래에 위치하게 되며, 이 main()이 호출하는 메서드들이 선입후출 방식으로 Call Stack에 쌓이게 된다.
    • 가장 나중에 실행된 메서드가 가장 먼저 종료하고, 가장 먼저 실행한 메서드가 가장 마지막으로 종료 (선입후출) 하여 자료구조에서는 이런 구조를 스택(Stack) 이라 이야기한다.
  • Heap

    • 프로그램이 실행되면서 생성되는 모든 인스턴스가 할당되는 공간이다.
    • new 키워드로 생성된 인스턴스 변수들이 할당되는 곳이라고 이해하면 된다.
    • Heap 메모리는 메서드 호출이 끝나도 인스턴스들이 계속 유지되는데, 그러다 참조하는 주소를 잃게되면 GC에 의해 지워지면서 Heap 메모리에서도 제거된다. 사용이 끝나도 계속 유지되는 Method Area와 다른 특징이다. Method Area에 할당하는 키워드는 static, Heap에 할당하는 키워드는 new 라는게 직관적으로 이해가 될 것 같다.

정리하면,

컴파일되어 생성된 클래스 파일을 JVM이 실행하면 클래스 파일을 분석하여 static 키워드의 클래스 정보만을 JVM의 메모리 영역 중 Method Area에 저장한다. Method Area는 고정적(static)이므로 프로그램 종료시까지 언제든 사용가능하다.

Call Stack에서는 main() 부터 실행하여 main()에서 실행한 다른 메서드를 호출한다.

이 과정에서 생성되는 인스턴스는 Heap 메모리에 저장되고, 인스턴스라는 이름과 Heap 이라는 단어처럼 Heap 메모리에 저장된 인스턴스는 호출될 때에만 사용되고, 사용이 끝나면 바로 소멸되는 동적인(dynamic) 특징이 있다. 이는 정적인(static) Method Area와 대비되는 특징이다.


그럼 언제 인스턴스를 사용해야 하는걸까?

정적할당 vs 동적할당

인스턴스의 공통적인 데이터 또는 자주 사용해야하는 데이터의 경우는 고정적(static)일 필요가 있다. 이런 데이터는 static 키워드를 선언하여 Method Area에 한 번 할당해두면, 필요할 때마다 참조만 해서 사용할 수 있다. 메모리 관리에 효율적이다.

그러나 Method Area에 할당되면 프로그램 종료시까지 메모리를 사용한다는 특징이 있다. 따라서 프로그램 종료시까지 지속적으로 필요한 데이터가 아닌 잠깐만 필요하거나 각 객체 별로 서로 다른 값을 저장하고 있어야 할 경우에는 Heap 메모리에 임시적으로 인스턴스를 생성하는 방법이 메모리 관리에 효율적이다. Heap 메모리는 Method Area와 달리 사용 후 즉시 폐기된다.


One more thing.

Heap 영역에서 참조타입 변수인 객체나 배열을 Null 값으로 받으면, NullPointException이라는 예외가 떠서 사용할 수가 없다. 이 때엔 초기값을 넣어서 Null값을 없애야 한다.