JVM 의 내부 구조와 작동원리

유정현·2024년 3월 26일

개요

JAVA VirtualMachine은 기계어를 소프트웨어로 동작하게끔 도와주는 녀석이라고 생각하면 된다. JVM 실행시 컴퓨터는 JVM에 일정 메모리를 빌려주고 할당받은 메모리로 JVM은 프로그램을 실행시킨다. Spring을 해본 사람들은 알겠지만 웹서버가 리눅스 위에서 배포되는 것, JAVA의 main(String[] args)를 실행하는것 등 모두 JVM이 컴퓨터로부터 메모리를 할당받아 실행되는 것이다.

대략적 순서

JVM은 스태틱으로 정의된 값들을 체크하여 메모리 위에 올려둔다. 이때부터 스태틱 변수, 메소드들은 계속해서 재사용된다. 그 다음에 인스턴스 등을 메모리에 올라간다. 즉, 지속적으로 하나를 두고 사용하는 것들이 먼저 올라간 다음에 우리 코드를 읽으며 필요한 것들이 메모리에 올라가면서 작동되는 것이다.

JVM 구조

JVM에는 여러가지가 있다. 다들 각자의 역할들이 있다.

  1. 자바 컴파일러
    자바 컴파일러는 우리가 자바코드로 만든 것들이 바이트코드(기계어)로 변환한다. 그런 다음 컴파일된 바이트코드를 JVM이 읽어나간다.
  2. ClassLoader
    클래스 로더는 JVM 내로 필요한 클래스 파일을 로드하고, 링크하는 과정을 통해 배치한다. 이런 링크를 통해 런타임 시에 동적으로 클래스를 로드할 수 있는 것이다.
  3. GarbageCollector
    가비지 컬렉터는 내부적으로 YoungGeneration, OldGeneration, Card 등 여러가지 동작 방식이 있다. 보통 지속적으로 사용되는 것을은 OldGeneration 영역으로 옮겨지고 금방 연결이 끊기는 것들은 YoungGeneration 영역으로 옮겨져서 각 영역이 꽉 찼을 때 GC가 활성화 되어 정리된다.
  4. Execution Engine
    ClassLoader를 통해 들어온 바이트 코드들을 명령어 단위로 읽어서 실행한다. 여기서 포인트가 될 수 잇는 것들은 명령어를 읽는 방식인데 JIT컴파일러 방식과 인터프리터 방식 두 가지를 함께 사용한다.
  5. Rundtime Data Area
    이 영역은 5가지로 나뉜다. 이 내용이 그래도 가장 이해하기 쉽다. MethodArea, HeapArea, StackArea 등 설명한 부분들이 많다.

직접 공부하며 그린 이미지

아래 내용이 곧 위 내용을 그림으로 그린 것이다. 쭉 살펴보면

  1. javaCompiler가 class파일을 만들어준다.
  2. JVM에 들어간다.
  3. ExecutionEngine을 통해 코드를 읽어내고 실행하며, 이때 RuntimeDataArea영역이 실행되는 영역이다.
  4. ClassLoader는 필요한 클래스들을 로드하고 링킹하는 곳이다.
  5. GC는 영역이 가득 찼을 때 청소를 해주는 것이다.

실제 런타임시

자 하지만 늘 그렇듯 이론과 실제는 다르다. 우리는 늘 스레드를 통해 프로그램을 작동시킨다. 그리고 스레드는 한 두 개가 아니다. 그리고 스레드는 각각의 인스턴스를 갖고 있고 공유하는 존재가 아니다. 그렇다 런타임이 되면, Runtime Data Area는 많이 달라진다. 아래가 그 해당 그림이다.
런타임이 되면, Thread 별로 Stack영역과 PC Register, native method stack 등을 할당 받는다. 이에 해당하는 각 영역에 대한 설명은 다음 포스팅으로 미룬다. 어쨌든 넓게 보면 영역은 저렇게 그려지는 것이 맞다.

마무리

이번 포스팅은 JVM의 대략적 구조를 정리해봤다. JVM의 구조를 아는 것은 JAVA에 대한 이해도를 높혀준다. 오랜만에 예전의 기록을 정리하다보니 조금 머리가 맑아지는 기분이 든다. 앞으로 이전 글들을 가져와 조금씩 정리하며 가다듬는 과정을 거칠 예정이다. JVM 마무리, MSA, Docker, Redis 등 가능한 공부하고 질 좋은 글들을 정리해봐야겠다.

1. JVM - CLASSLOADER 정리

2. JVM - ExecutionEngine 정리

profile
코딩하는 감자입니다.

0개의 댓글