Java

[Java] JVM 구조와 메모리 사용영역, Java 쓰레드와 메모리 구조

nooblette 2023. 11. 5. 19:37

목차

    배경

    Java의 동작원리와 문법을 제대로 깊게 공부해본 적이 없어 이번 기회에 다시 학습하는 중인데 그 중 자바 실행 환경인 JVM과 기본적인 메모리 구조는 공유해두면 많은 도움이 될 것 같아 블로그에 별도로 기록해두었다.

    JVM(Java Virtual Machine)

    자바 프로그램 실행환경을 만들어 주는 소프트웨어
    자바 코드(.java)를 컴파일하여 .class 바이트 코드로 만들면, 이 코드를 JVM 환경에서 실행
     

    JVM 구조

    메모리 주소상 위치 : Low address(0x0000000) ~ High address(0xFFFFFFFF)
    Heap 영역은 낮은(Low) 메모리 주소에서 높은(High) 메모리 주소로 할당받으며, Stack 영역은 그 반대이다.

    출처 : https://thsd-stjd.tistory.com/149

    JVM Runtime Data Area

    출처 : https://www.devkuma.com/docs/jvm/memory-structure/

    java 명령어로 JVM(java virtual machine)을 구동하며, JVM은 운영체제에서 할당받은 메모리 영역을 다음과 같이 구분하여 사용하며 그 구조를 나타내면 위 이미지와 같다.
     
    1. 메소드 영역(method area)

    • JVM이 실행되면서 생기는 공간
    • 프로그램을 실행하는 자바 코드(Class 정보, 전역 변수, 상수 필드, static 필드, 메소드 코드, 생성자 코드)를 포함
    • 바이트코드 파일(.class)의 내용이 저장되는 영역
    • 모든 Thread에서 정보가 공유된다.

     
    2. 힙 영역(heap area)

    • new 연산자로 객체를 생성하거나 Array를 동적으로 생성하면서 데이터가 저장되는 공간
    • 객체, 배열 등을 포함하여 참조 타입 변수의 실제 데이터가 저장되는 영역
    • Garbage Collector가 처리하지 않는 한 Heap에 저장된 데이터는 소멸되지 않는다.
    • 스택 영역에서 생성되는 참조 변수는 객체의 주소인 힙 영역의 메모리 주소를 참조한다.
    • 힙 영역은 새로운 데이터가 추가될수록 더 높은(High) 메모리 주소를 할당받는다(스택 영역의 메모리 할당 규칙과 정 반대이다)
    • 스택 영역과 힙 영역은 공유 라이브러리 영역을 가운데에 두고 서로 마주보기 때문에 메모리 공간을 알뜰하게 활용할 수 있다.
    • 모든 Thread에서 정보가 공유된다.

     
    3. 스택 영역(stack area)

    • 지역 변수, 매개변수 등과 같이 잠시 사용 되고 필요가 없어지는 데이터가 저장되는 영역
    • 메서드가 호출될때마다 메서드 프레임(method frame)이 생성되고 저장되는 영역
    • 메소드 호출이 끝나면 메서드 프레임은 자동 제거된다.
    • 프레임 내부에 로컬 변수 스택(local variable stack)이 존재
    • 기본 타입 변수와 참조 타입 변수가 생성되고 제거되는 영역이다.
    • 스택 영역은 항상 kernel의 반대방향으로 자라기 때문에 영원히 kernel을 만나지 않게 된다. 따라서, 스택이 아무리 커져도 커널은 건드리지 않는다.
    • Thread 마다 하나씩 존재한다.

     
    4. PC Register

    • Thread가 생성되면서 생기는 공간
    • Thread가 어느 명령어를 처리하고 있는지 그 주소를 등록한다.
    • JVM이 실행되고 있는 현재 위치를 저장하는 역할
    • Thread 마다 하나씩 존재한다.

     
    5. Native Method Stack

    • Java가 아닌 다른 언어(C, C++)로 구성된 메소드 실행이 필요할때 사용되는 공간
    • Thread 마다 하나씩 존재한다.

    Thread 구조

    Thread는 한 Process 내에서 Heap, Method Area 영역을 공유하며 독립적인 Stack, PC Register, Native Method Stack 영역을 갖는다. 한 프로세스 내에서 동작되는 여러 Thread는 프로세스 내의 주소 공간이나 자원(Method, Heap Area)을 공유하며 독립적인 작업을 수행하기 위한 Stack과 PC Register, Native Method Stack 영역을 갖는다.

    Thread와 Memory 구조

    출처 : https://thsd-stjd.tistory.com/149

    한 Process 내에 여러개의 Thread가 존재하고 각 Thread 영역 내부에 독립적인 Stack area가 존재, 다시 각 Stack area 내부에 여러개의 method frame이 존재한다.

    Stack을 Thread 마다 독립적으로 할당하는 이유

    스택은 한 번 사용하고 나면 더이상 사용하지 않는 변수 즉, 함수 호출시 전달되는 매개변수나 지역변수 등을 저장한다. 스택 영역이 독립적이라는 말은 독립적인 함수 호출이 가능하다는 의미이며, 이는 한 프로세스 내에서 독립적인 실행 흐름을 가능케한다. 따라서 Thread의 독립적인 실행 흐름을 위한 최소 조건으로 독립적인 Stack Area를 할당한다.

    PC Register를 Thread 마다 독립적으로 할당하는 이유

    이 이유를 이해하기 위해서는 두가지 개념을 알고있어야 한다. 첫번째는 Thread는 CPU를 할당받았다가 Scheduler에 의해 다시 선점(pre-emption)당한다는 것이고 두번째는 PC Register 영역은 Thread가 어느 명령어를 처리하고있는지 즉, 현재 JVM이 실행되고 있는 위치를 저장한다는 것이다.
    OS(운영체제)의 Scheduler는 어떤 프로세스가 CPU를 할당받을지 정하는데, 이때 Stack Area의 한 Thread에게만 CPU를 할당하여 동작하다가 스케쥴링에 의해 CPU를 다른 Thread에게 할당하고 기존에 할당받았던 Thread가 대기(Waiting) 상태로 들어간다면, 그리고 후에 다시 CPU를 할당할때 대기중이던 Thread가 어느 지점까지 동작하고 있었는지를 알고 있어야 한다. 이 실행되고 있던 어느지점(= 독립적인 실행 흐름) 또한 Thread 마다 할당되기 때문에 PC Register 영역도 Thread마다 독립적으로 할당한다.


    출처