3 분 소요


JVM 이란?

JVM(Java Virtual Machine) 은 자바와 운영체제 사이에서 중개자 역할을 수행하며 자바가 OS에 의존하지 않고 프로그램을 실행할 수 있게 도와준다. 또한 가비지 컬렉터(GC)를 사용한 메모리 관리도 자동으로 해주며, 다른 하드웨어와 다르게 레지스터 기반이 아닌 스택 기반으로 동작한다.



특징

img1

자바 컴파일러(javac) 에 의해서 자바 소스 파일(.java)가 바이트 코드(.class) 로 컴파일된다. 그리고 이를 JVM 이 읽고 내부적으로 여러 과정을 거쳐서 실행시킨다.

위 그림에서 알 수 있듯이 JVM은 OS에 의존한다. 때문에 각 OS 마다 다른 JVM이 요구된다. javac 에 의해 컴파일된 바이트 코드는 JVM에서 처리되기 때문에 OS에 의존하지 않는다.

Write once, run anywhere



실행 과정

img4

그렇다면 JVM의 실행 과정에 대해서 간단하게 알아보자!

  1. 자바 프로그램을 실행하면 JVM은 OS로부터 메모리를 할당받는다.
  2. 자바 컴파일러(javac) 이 자바 소스코드(.java) 를 자바 바이트 코드(.class)로 컴파일 해준다.
  3. Class Loader 가 동적 로딩을 통해 필요한 클래스들을 로딩 및 링크해서 Runtime Data Area에 올린다.
  4. Runtime Data Area에 로딩 된 바이트 코드는 Execution Engine 을 통해서 해석된다.
  5. 이 과정에서 Execution Engine에 의해 GC가 작동하고 쓰레드 동기화가 이루어진다.



JVM 메모리 구조

JVM의 구체적인 수행과정에 대해서 알아보자.

img2

Class Loader

  • 클래스 로더는 JVM내로 클래스 파일(*.class)을 동적으로 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.
    • .class 파일을 엮어서 JVM의 메모리 영역인 Runtime Data Areas 에 배치한다.
    • Loading -> Linking -> Initalization 과정을 거친다.
      • Loading : 클래스 파일을 가져와서 JVM 메모리에 로드한다.
      • Linking : 클래스 파일을 사용하기 위해 검증한다.
      • Initialization : 클래스 변수들을 적절한 값으로 초기화한다. (static 필드를 설정한 값으로 초기화, 등등)


Execution Engine

  • 클래스 로더를 통해 Runtime Data Areas 에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다. 기본적으로 인터프리터 방식을 사용해서 읽다가 일정 기준을 넘어가면 JLT 컴파일 방식으로 어셈블러 같은 네이티브 코드로 바꿔서 실행한다.
    • JTL : 바이트 코드 전체를 컴파일해서 네이티브 코드로 변경하고 이후 메서드를 인터프리팅 하지 않고 캐싱해 두었다가 네이티브 코드로 직접 실행하는 방식이다. 네이티브 코드로 변경하는 것도 비용이 있음으로 JVM은 모든 코드를 JLT 방식으로 실행하지는 않고 인터프리터 방식을 사용하다가 일정 기준을 넘어가면 JLT 컴파일러가 작동하는 방식을 사용한다.
    • Interpreter : 바이트 코드 명령어를 하나씩 읽어서 해석하고 바로 실행한다. 같은 메소드라도 여러번 호출이 된다면 매번 해석하고 수행해야 되서 전체적인 속도는 느린 편이다.


Garbage Collector

  • GC는 힙 메모리 영역에 생성된 객체들 중에서 참조되지 않는 객체들을 탐색해서 제거하는 역할을 한다. GC가 실행되는 시점은 정확하게 알 수 없다.

  • 수동으로 GC를 실행하기 위해 System.gc() 를 호출할 수 있지만, 실제 함수 실행은 보장되지 않는다.


Runtime Data Area

  • JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다. 이 영역은 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack으로 나뉜다. Method Area, Heap Area는 모든 쓰레드가 공유하고 나머지는 각 쓰레드마다 생성되는 개별 영역이다.

img3


Method Area

  • 모든 쓰레드가 공유하는 영역이다. 클래스, 인터페이스, 메소드, 필드, Static 변수 등의 바이트 코드를 저장한다.
  • JVM이 동작하고 클래스가 로드될 때 적재되서 프로그램 종료될 때까지 유지된다.
  • Class Area, Static Area 로도 불린다.


Heap Area

img3

  • 마찬가지로 모든 쓰레드가 공유하며, new 키워드로 생성된 객체와 배열이 생성되는 영역이다. 메소드 영역에 로드된 클래스만 생성이 가능하고 GC가 작동하는 영역이다.
  • Heap Area는 GC를 효율적으로 작동시키기 위해서 또 5가지 세부 영역으로 나뉜다.
    • Young Generation : 생명 주기가 짧은 객체를 GC 대상으로 하는 영역
      • Suvivor 0 / Survivor 1 : 각 영역이 채워지게 되면, 살아남은 객체는 비워진 Survivor로 순차적으로 이동
      • Eden : new를 통해 새로 생성된 객체가 위치한다. 정기적인 GC후 살아남은 객체는 Survivor로 이동된다.
    • Old Generation : 생명 주기가 긴 객체를 GC 대상으로 하는 영역, Yuoung Generation에서 마지막까지 살아남은 객체가 들어온다.


Stack Area

  • 메서드를 호출할 때마다 각각의 스택 프레임이 생성된다. 그리고 메서드 안에서 사용되는 값들을 저장하고, 호출된 메서드의 매개변수, 지역변수, 리턴 값 및 연산할 때 생성되는 값들을 임시로 저장한다. 메서드 수행이 끝나면 프레임별로 삭제된다.


PC Register

  • 쓰레드가 시작될 때 생성되는 공간으로 쓰레드마다 하나씩 존재한다. 쓰레드가 어떤 부분을 어떤 명령으로 실행해야 하는지에 대한 기록을 하는 부분이다. 현재 수행중인 JVM의 명령 주소를 가진다.


Native method stack

  • 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역이다.



참고 사이트 출처

https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8

https://steady-coding.tistory.com/305

태그: ,

카테고리:

업데이트: