Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save taekwon-dev/3563a5b0794518ee4f1222bcaebf1d70 to your computer and use it in GitHub Desktop.
Save taekwon-dev/3563a5b0794518ee4f1222bcaebf1d70 to your computer and use it in GitHub Desktop.

[Java] How is a Java Program executed [3-1] JVM 구성 요소 - Runtime Data Area

지난 글에서는 JVM 의 구성 요소 중 .class 파일을 읽어 메모리의 메서드(Method) 영역에 로드하는 클래스 로더에 대해 알아봤다. 사실 클래스 로더에서 다룬 글에서 이미 오늘 다룰 메모리에 관한 내용이 포함되어 있었는데, 이번 글에서는 JVM 메모리에 대해 보다 자세히 다룰 예정이다.

실행 파일 형태의 프로그램이 실행 중 상태에 있을 때 우리는 이를 프로세스(Process) 라 부른다. 이를 또 메모리 관점에서 설명하면 메인 메모리(RAM)에 프로세스가 올라가있는 상태로도 설명할 수 있다.

image

[ 그림 1 ]

[ 그림 1 ] 는 프로세스가 메모리에서 어떻게 관리되는지를 보여준다. 여기서 말하고 싶은 핵심은 프로그램이 실행될 때 메모리에서 해당 프로세스를 관리하기 위해 여러 정보들이 올라가 있다는 점이다.

이제 다시 자바 프로그램의 실행 맥락으로 다시 돌아와보자. 위 내용을 기반으로 자바 프로그램의 실행과 관련해서도 필요한 데이터들이 메모리에 올라간다는 생각해볼 수 있다. 단, 자바 프로그램이 실행되면 JVMOS 로부터 해당 프로그램이 필요로하는 메모리를 할당 받고, JVM 은 할당 받은 메모리를 여러 영역으로 나누어 관리한다. 이 내용을 기반으로, 자바 프로그램이 OS 와의 관계에서 JVM 을 매개로 실행되는 관계를 메모리 관점에서도 이해할 수 있다.

image

[ 그림 2 ]

[ 그림 2 ] 의 메모리(Runtime Data Area) 를 보면 5개의 세부 영역으로 나뉘어 있는 것을 볼 수 있다.

  • Method
  • Heap
  • Stack
  • PC Register
  • Native Method Stack

위 목록 중 [ 그림 2 ] 에서 Method , Heap모든 스레드에서 공유한다는 점에서 다른 영역과 다른 색으로 표시했다. 지금부터 각 영역에서 어떤 정보들이 저장되고 관리되는지 알아보자.


| Method

클래스 로더는 .class 내 바이트 코드를 읽어 JVM 메모리의 Method 영역에 클래스 메타 데이터(아래 목록 참고)를 저장한다.

  • FQCN (Full-Qualified Class Name)
  • Type 정보 (Interface, Class, 또는 Enum)
  • 인스턴스 변수, 메서드, 생성자, 정적 변수

객체 생성을 위한 필요한 정보가 저장되어 있는 곳으로, 프로그램 시작부터 종료될 때 까지 다시 말해 프로그램 생명주기 내 지속적으로 메모리에서 로드되어 있는 영역이다. 또한 앞서 언급한 것과 같이 모든 스레드에서 공유하는 공간이다.


| Heap

Heap런타임new 를 통해 생성된 객체 또는 배열이 저장되는 영역이다. 클래스 로더 설명 중, 로딩 후 Class 타입의 객체를 생성해 Heap 영역에 저장한다고 했었는데, 해당 내용과 같이 런타임 시 생성된 객체가 저장되는 공간으로 이해하면 된다.

Heap 영역은 다른 글을 통해 다룰 Garbage Collector 와 밀접한 관계가 있다. Garbage Collector 는 참조되지 않은 객체(unreachable object)를 제거해주는 역할을 담당하는데, 앞서 설명한 것과 같이 런타임 시 생성된 객체가 저장되는 영역이 Heap 이므로 Garbage Collector 의 주 활동 영역이 된다.


| Stack

Stack 부터 아래에 등장하는 각 요소는 모두 스레드 별로 따로 할당된다.

image

[ 그림 3 ]

각 스레드 별로 메서드를 호출하면, [ 그림 3 ] 와 같이 StackStack Frame 이 쌓이고, 메서드가 종료된 경우 Stack 자료 구조 특성과 같이 위에서 부터 하나씩 Stack Frame 이 제거(pop)된다.

Stack Frame 내에는 Local Variable(지역 변수) 정보와 Operand Stack , Constant Pool Reference 를 포함하고 있다.

Operand Stack 에는 메서드 내 연산을 위한 명령어가 저장된 작업 공간이고, Constant Pool Reference 는 말 그대로 Constant Pool 참조를 위한 공간이다.

image

[ 그림 4 ]

image

[ 그림 5 ]

예를 들어, [ 그림 4 ] 의 main() 메서드가 호출되는 경우를 생각해보자. 메서드가 호출되면, [ 그림 5 ] 과 같이 Stack FrameStack 에 추가되고, Local Variable 에 해당하는 args, varStack Frame 내에서 저장되어 있다. 이 때 var 변수와 같이 Constant Pool 을 참조하는 경우, 앞서 언급한 것과 같이 Stack FrameConstant Pool Reference 내에서 해당 참조를 관리하게 된다.


| Native Method Stack

자바 프로그램에서 자바가 아닌 언어(C, C++)로 작성된 API 를 사용하는 경우가 있다. 이런 메서드를 네이티브 메서드라고 하고, 해당 메서드가 바이트 코드가 아닌 기계어로 작성되어 있으므로 JVM 이 이를 처리할 때는 기계어를 다시 바이트 코드로 변환되어야 한다.

image

[ 그림 6 ]

기계어 ► 바이트 코드 변환 작업을 위해 [ 그림 6 ] 의 Native Method Interface 를 활용한다. Native Method 활용 예로, 자바 코드로 작성된 메서드를 수행하다가 Native Method Interface 를 통해 Native Method 를 호출하는 경우가 있다. 이 때 Native Method Stack 에 Frame이 쌓이고, StackNative Method Stack 은 동적 연결(Dynamic Linking)을 통해 연결된다.


| PC Register

image

[ 그림 7 ]

[ 그림 7 ] 은 1개의 CPU 가 시분할 방식으로 프로세스를 처리하는 것을 보여준다.

image

[ 그림 8 ]

[ 그림 7 ] 에서 1개의 CPU 가 여러 개의 프로세스를 매우 짧은 시간동안 실행하는 것을 반복(= 시분할 방식)하면서 우리 눈에는 마치 여러 개의 프로세스가 동시에 실행되는 것 처럼 보인다.

이 때 각 프로세스가 대기 상태(CPU 점유 X)에 있다가 실행 상태(CPU 점유 O)로 다시 돌아올 때 이전에 진행 했던 코드(명령어)부터 시작해야 하는데, 이 때 이러한 정보를 PC(Program Counter) 에 저장한다.

자바의 PC Register 역시 위 내용과 같은 맥락을 가지고 있고, 이 곳에 각 스레드 별로 스레드가 실행할 스택 프레임 정보를 가리키는 포인터 정보를 저장한다.


| Reference

JVM에 관하여 - Part 3, Run-Time Data Area

Where Does Java’s String Constant Pool Live, the Heap or the Stack? | Baeldung

JVM stack과 frame - 기계인간 John Grib

What is Java String Pool? | DigitalOcean Java 런타임 데이터 영역 :: 스터디룸

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment