메모리 관리

JVM Memory Architecture

stack

  • 스레드 생성 시 할당된다

  • 메서드 실행 관련 정보가 프레임 단위로 저장된다

  • 너무 많은 메서드가 호출되어 스택에 쌓이게 되면 흔히 볼 수 있는(?) StackOverFlowError가 발생한다.

  • 스택을 생성하거나 동적으로 크기를 확장할 때 메모리가 부족하면 OutOfMemoryError가 발생한다.

  • 프레임

    • JVM stack에 생성되는 메서드 관련 정보 저장 단위

    • 메서드가 호출될 때 생성(push)되며 종료되면 소멸(pop)됨

    • 각 프레임에는 런타임에 필요한 메서드 참조를 위해 런타임 상수 풀 참조를 포함

    • 구성 요소

      • Local Variables

        • 매개 변수와 지역 변수를 저장

        • 컴파일 타임에 결정되며
 관련 메서드, 클래스 등의 정보와 함께 바이트코드로 제공

        • JVM에 의해 메서드 호출 시 매개 변수(또는 Args)는 지역 변수 배열에 담겨 전달

        • 인스턴스 메서드 호출 시 지역 변수 0은 인스턴스 메서드 객체 참조인 this를 전달하는데 사용
하고 1부터 매개변수들이 표현된다

      • Operand Stack

        • 실행 중간 연산 결과 등을 임시로 저장해두는 스택으로 push/pop 명령어에 의해 액세스 가능

        • JVM은 지역 변수, 필드의 값을 오퍼랜드 스택으로 로딩하는 명령을 제공하며


          다른 명령들을 통해 오퍼랜드 스택에서 값을 가져와 연산, 결과를 다시 저장함

        • 호출할 메서드에 전달할 매개 변수 전달과 결과를 수신할 때도 사용됨

      • Frame Data

        • 연관된 메서드의 심볼릭 레퍼런스와 메서드 반환에 필요한 정보 저장

        • 예외가 발생한 경우 catch 블록 정보를 제공하는 Exception 테이블 참조 포함

Heap

  • JVM 실행 시 생성되어 모든 객체의 인스턴스, 배열 등이 할당되는 영역

  • 모든 스레드와 공유해 thread-safe하지 않아 문제가 될 수 있다.

  • 힙의 크기는 상황에 따라 유동적이며, 순차적일 필요가 없다.

  • 공식적으로 GC가 처리되는 유일한 영역

Stack Memory vs Heap Memory 비교

  • 스택 메모리

    • 메서드 실행/완료에 따라 메모리 크기가 변경된다.

    • 메모리 크기는 OS에 의존적이며 보통은 힙보다 작다.

    • 메모리 할당 속도가 매우빠르다.

    • 메모리 할당과 해제는 메서드 호출에 따라 이뤄진다.

    • 스레드 별로 할당되어 thread-safe 하다.

  • 힙 메모리

    • Young Generation, Old Generation 같은 메모리 엑세스 기술이 활용된다.

    • 메모리 크기에 제한이 없어 생성된 모든 객체를 저장한다.

    • GC에 의해 메모리가 관리된다.

    • 메모리를 여러 스레드들이 접근하여 thread-safe하지 않다.

Method

  • JVM 실행 시 생성되어 모든 스레드에게 공유된다

  • 클래스 별 구조나 메타 데이터를 저장

    • 초기화에 사용되는 스페셜 메서드(인스턴스 초기화 메서드, 클래스 초기화 메서드, 런타임에 메서드 시그니처가 결정되는 메서드)

    • 런타임 상수 풀, 필드/메서드 데이터

    • 생성자/ 메서드 코드

  • 논리적으로는 힙의 일부이다

  • 메서드 영역의 크기는 유동적이다.

런타임 상수 풀

  • 클래스/인터페이스가 로딩되어 생성될 때 Method 영역에 할당되는 자료구조

  • 컴파일 시 `.class` 파일에 생성되는 일반 상수 풀의 런타임 표현

  • 일반 상수 풀의 데이터를 기반으로 생성되며 스태틱 상수, 스태틱 메서드, 심볼릭 레퍼런스(또는 실제 참조) 등을 포함

상수 풀

  • Java 바이트코드에 포함되어 있는 모든 상수 값을 저장하는 심볼(룩업) 테이블


  • .java 파일이 Java 컴파일러에 의해 컴파일 되어 Java 바이트코드로 변환될 때 생성

  • 클래스명, 필드명, String/Primitive type 리터럴, 심볼릭 레퍼런스 등이 저장됨

  • 컴파일 타임 시점에 알 수 있는 정보들이 저장되며, 런타임 시점에는 런타임 상수 풀로 일부 데이터가 이동한다.

  • 상수 풀에서 런타임 상수 풀로 가는 경우

    • 심볼릭 레퍼런스나 String.intern 등 런타임에 달라질 수 있는 데이터

    • 컴파일 타임에 확정되어 런타임에 변경되지 않는 데이터(리터럴 값 등)들을 제외한 데이터

Native Method Stacks

  • JNI, 네이티브 라이브러리 사용 시 데이터가 저장되는 영역

PC Register

  • 스레드 생성 시 생성/할당되며 현재 실행 중인 명령의 주소를 저장하는 영역

  • 레지스터는 프로세서 내에서 자료를 보관하는 빠른 기억 장치

  • 저장되는 명령의 주소는 Java 바이트 스트림(바이트코드) 안에 오프셋을 의미

  • 자바 메서드의 경우에만 실행 명령의 주소 저장한다. (opcode)

  • JNI 메서드는 저장되지 않는다.

Last updated