JVM

jyKim·2023년 1월 27일
0

Java

목록 보기
1/3

자바 동작 원리

  • JVM을 알기 전 우선 자바의 실행 구조를 알아야한다.
  • Java는 완전하게 interpreter 되거나 compile 되지 않는 언어로서, 두 형태의 조합을 사용한다.
  • 아래부터 자바의 특징 및 동작 원리를 설명합니다.

플랫폼 독립성

  • 대부분의 프로그래밍 언어의 컴파일러(혹은 인터프리터)는 특정 대상 시스템에서 만 실행될 수 있는 코드를 생성한다. 예시로 윈도우에서 컴파일 된 C++프로그램은 Linux에서는 실행이 불가하다. 플랫폼은 운영체제와 함께 대상 시스템에 의해서 결정된다.
  • Java 컴파일러는 타겟의 개체 파일을 생성하지 않고 가상 시스템(Virtual Machine)의 개체 파일인 바이트코드(bytecode)를 생성한다. 이러한 특징 때문에 Java 컴파일러는 때로 JVM 컴파일러라고도 불린다.
  • 이러한 특징으로 인해 어느 플랫폼에서든 Java프로그램을 작성하고 JVM 컴파일러(javac)를 통해 바이트 코드를 생성할 수 있다. 이때 바이트코드는 .class 확장자를 가진다. 이때 중요한 점은 .class파일은 실행 파일이 아니다.
  • 바이트 코드(.class) 파일을 실행하기 위해서는 자바 인터프리터를 호출해야 한다. 각 플랫폼에는 Java 인터프리터가 존재하며, 해당 인터프리터는 바이트코드를 적정한 코드로 연결해준다.
  • 이때 생성된 바이트코드는 어느 플랫폼에서든 동일하게 실행 가능하다. 즉, 플랫폼은 각 플랫폼의 JVM을 가지고 있을 뿐, 바이트코드의 실행 결과는 모든 운영체제에서 동일한 것이다.. 이것이 자바가 플랫폼 독립적인 이유이다.
  • 그렇기에 JVM에 의해 실행되는 바이트코드를 생성하는 언어라면 굳이 자바가 아니더라도 JVM을 통해 실행이 가능하게 된다. 이러한 언어 중 가장 대표적인 언어가 바로 Kotlin이다.

Java 실행 구조

  • Java는 고급 프로그래밍 언어이다. 즉, 컴퓨터가 이해할 수 없으며, 실행할 수 없다. 따라서 기계어로 번역이 필요하다. 이 작업을 수행하는 것이 자바 컴파일러이며, 자바 프로그램(.java)를 바이트코드(.class)로 변환한다.
  • 그리고 이 바이트코드를 JVM이 실행하는 것으로 자바 프로그램이 실행된다. 이때, 인터프리터(혹은 JIT 컴파일러)가 이 바이트코드를 기계어로 변환 및 연결한다.
  • 이 실행 구조를 그림으로 나타내면 아래와 같다.

java-model

  • 하지만 이러한 구조로 인해 자바는 상대적으로 느린 속도를 가지게 되었다.
  • Java가 느린 이유
    1. 동적 연결 → C같은 언어와 달리 연결은 프로그램이 Java에서 실행될 때마다 런타임에서 수행된다.
    2. 런타임 인터프리터 → 바이트코드를 원시 기계어로 변환하는 과정이 Java 런타임에서 수행되므로 속도가 느려진다.

JIT Compiler

  • 프로그램을 실제 실행하는 시점(Runtime)에 기계어로 번역하는 컴파일 기법이다.
  • 인터프리터는 컴파일러와 달리 실행하는 시점에서 필요한 부분을 해석하는 방식이다. 이는 동일한 코드가 여러번 사용될때마다 매번 해석하기 때문에 속도가 느린 단점이 있다. 이를 개선하여 성능을 향상하고자 JIT 컴파일러가 등장했다.
  • JIT 컴파일러는 같은 코드를 매번 해석하는 대신 처음 실행될 때 인터프리트를 수행하며 자주 쓰이는 코드를 캐싱한 뒤, 이후에는 캐싱된 코드를 가져다 사용하기에 인터프리터의 느린 실행 속도를 개선할 수 있다.
  • 단점은 초기 구동 시 실행단계에서 컴파일하는 것에 시간과 메모리를 소모하기 때문에 실행 속도 면에서 손해를 보게 된다.

JVM?

  • Java Virtual Machine을 말하며, 요약하면 자바를 실행하기 위한 가상 머신을 말한다.
  • JVM은 실제 시스템(사용자 PC)에 상주하는 가상 시스템이며, JVM의 시스템 언어는 바이트코드이다. 따라서 JVM은 .java 파일을 컴파일하여 .class 파일을 생성하는 java 컴파일러(javac)가 필요하다.
  • JVM 컴파일러는 JVM에 대한 바이트 코드만 생성하면 되므로, 컴파일러가 일을 처리하기 쉽게 만든다.
  • JVM은 컴파일러에 의해 생성된 바이트 코드를 실행하고 출력을 생성하며, JVM이 자바를 플랫폼 독립적으로 만드는 것이다.

JVM 구조

  • Architecture

jvm-model

Class Loader

  • 위에서 말한대로 자바는 동적으로 클래스를 읽어오며, 런타임에서 모든 코드가 자바 가상 머신과 연결된다.
  • 이렇게 동적으로 클래스를 로딩해주는 역할을 하는 것이 Class Loader이다.
  • .class 파일을 묶어서 JVM이 운영체제로부터 할당받은 메모리 영역인 Rumtime Data Area로 적재한다.

Execution Engine

  • Runtime Data Area에 배치된 바이트코드를 명령어 단위로 읽어서 실행한다.
  • 이때 인터프리터 방식과 JIT 컴파일러 방식을 사용하며, 기본은 인터프리터 방식을 사용하다가 일정 기준이 넘어가면 JIT 컴파일러 방식으로 실행한다.

Garbage Collector

  • 가비지 컬렉터(GC)는 더이상 사용하지 않는 메모리를 자동으로 회수해준다.
  • Heap 메모리 영역에 생성된 객체 중 참조되지 않는 객체를 탐색 후 제거하는 역할을 수행하며, 역할을 수행하는 시간은 정확히 언제인지 알 수 없다.
  • GC를 수행할 때 해당 스레드를 제외한 나머지 모든 스레드는 일시정지 상태가 된다.

Runtime Area

  • 모든 스레드가 공유하는 영역(GC 대상)
    1. Method Area
      • 클래스, 인터페이스, 메소드, 필드, Static 변수, final class 등이 생성되는 영역이다.
    2. Heap Area
      • new 키워드로 생성된 객체가 생성되는 영역이다.
      • reference type 객체들이 저장되는 영역이다.
      • 주기적으로 GC가 제거하는 영역이다.
  • 스레드마다 하나씩 생성하는 영역
    1. Stack Area
      • 지역변수, 파라미터, 리턴 값, 임시 값 등이 생성되는 영역이다.
    2. PC(Program Counter) register
      • Thread가 생성될 때마다 생성되는 영역이다.
      • 현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있다.
    3. Native Method Stack
      • 자바 이외의 언어로 작성된 네이티브 코드를 실행할 때 사용되는 메모리 영역이다.

Reference

profile
백엔드애옹

0개의 댓글