[Java] 자바 실행 과정 및 구조

주재완·2024년 1월 18일
0

Java

목록 보기
3/13
post-thumbnail

목표

기본적으로 JVM으로 인해서 자바가 다른 언어들과 다른 특징이 있다고 알려져있다. 그럼 JVM이란 건 뭔지, 애초에 자바 실행 과정이 어떻게 되고 구조가 어떻게 되는지 알아보자.

JVM?

JVM(Java Virtual Machine) 자바 프로그램을 운영체제 및 하드웨어 관계없이 정상적으로 실행할 수 있게 해주고, 프로그램 메모리 관리 및 최적화 등 다양한 작업을 실행한다. 이 때, JVM이 이해할 수 있는 파일을 만들기 위해서는 자바 소스코드(.java)자바 바이트코드(.class)로 변환해주어야 한다. 그리고 이 과정을 하는 것이 바로 Java Compiler(javac) 이다.

실행 과정

실행 과정

자바 소스 파일(.java)을 자바 컴파일러(javac)가 자바 바이트코드(.class)로 만든다. 이 과정이 바로 터미널에서 아래와 같이 입력하면 진행된다.

$ javac 파일명.java

이후 자바 바이트코드를 JVM이 읽고 실행하게 된다. 이 과정이 터미널에서 다음과 같이 입력하면 진행된다.

$ java 파일명

자바 설치 및 시작에서 보았던 "Hello World!!" 출력하는 코드가 바로 이런 과정을 거쳐서 실행되는 것이다.

자바 바이트코드(.class)

자바 바이트 코드

  • JVM이 이해할 수 있는 언어이다.
  • 명령어 크기가 1 바이트라서 자바 바이트라 불린다.
  • 확장자는 .class이다.
  • JVM만 있다면 운영체제에 상관없이 정상적으로 실행 가능하다.

JIT(Just In Time) 컴파일러

JIT 컴파일

  • 프로그램을 실제 실행하는 시점에 컴파일하는 기법
  • 보통 프로그램을 만드는 방법은 인터프리트 방식정적 컴파일 방식이 존재
    • 인터프리트 방식은 실행 중 프로그래밍 언어를 읽어가면서 대응하는 기계어 코드를 실행하므로 번역과 실행이 동시에 이루어짐
    • 컴파일 방식은 실행 전에 코드를 기계어로 번역하고 실행하므로 번역과 실행이 별도의 과정으로 존재함
  • 위 두 방식을 혼합한 방식이 바로 JIT 컴파일러가 하는 일!
    • 실행 시점에서 인터프리트 방식으로 기계어 코드를 생성하면서 그 코드를 캐싱하여, 같은 함수가 여러 번 불릴 때 매번 기계어 코드를 생성하는 것을 방지

      캐싱 : 파일 복사본을 캐시 또는 임시 저장 위치에 저장하여 보다 빠르게 액세스할 수 있도록 하는 프로세스에 해당

JVM 구성요소

전체적인 구성은 아래와 같다.

JVM 구성요소

Class Loader

Class Loader는 클래스를 로드하고 링크하고 초기화한다. 또한 Runtime Data Area에 바이트코드로 배치하는 역할을 한다.

로드

  • 클래스(.class) 파일들을 JVM의 메모리로 읽어 들이는 것을 의미

링크

3단계 과정으로 구성되어 있다.

  • 검증(Verifying)
    • 읽어 들인 클래스가 자바 언어 명세(Java Language Specification) 및 JVM 명세에 명시된 대로 잘 구성되어 있는지 검사
    • 클래스 로드의 전 과정 중 가장 복잡하고 시간이 많이 걸림
  • 준비(Preparing)
    • 클래스가 필요로 하는 메모리를 할당하고, 클래스에서 정의된 필드, 메서드, 인터페이스들을 나타내는 데이터 구조를 준비
  • 분석(Resolving)
    • 클래스의 상수 풀 내 모든 symbolic referencedirect reference로 변경

      symbolic reference : 참고하는 클래스의 특정 메모리 주소를 참조 관계로 구성한 것이 아닌 참조하는 대상의 이름으로 참조하는 것

      direct reference : symbolic reference와 특정 메모리 주소를 참조하는 것

초기화

클래스 변수들을 초기화하는 과정이다. static 붙은 것들(static initializer 들 수행, static 필드 초기화)과 관련 있다고 생각하면 된다.

Execution Engine

데이터 영역에 배치된 바이트 코드를 해석한다.(Byte Code → Binary Code)

바이트 코드 해석 방식

  • 인터프리터
  • JIT 컴파일러 : 인터프리터 + 캐싱

Runtime Data Area

Runtime Data Area는 다음과 같은 구조로 되어있다.

Runtime Data Area

PC register, JVM Stack, Native Method Stack은 Thread마다 하나씩 생성되고 Heap, Method Area는 모든 Thread가 공유해서 사용하는 형태이다.

힙(Heap)

프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 메모리 영역. new 연산자를 통해 생성한 객체, 인스턴스를 저장하는 공간이고, GC가 실행되기도 한다.

GC(Garbage Collector) : 자세한 방식은 후 포스팅에서 추가 예정이지만, 사용하지 않는 메모리는 시간이 지난 후 처리해주는 역할 (메모리가 초과할 경우 등등…)

메서드(Method)

클래스 정보, 변수 정보, Method 정보, static 필드 정보, 상수 정보 등이 저장되는 영역이다.

쓰레드(Thread)

아래 있는 것들은 한 쓰레드 내부 존재하고, 각 쓰레드 별로 별개로 존재한다.

PC 레지스터(PC Register)

현재 수행 중인 JVM 명령의 주소를 갖는다. 어떤 부분을 어떤 명령으로 실행할지를 기록하며 현재 명령과 주소를 저장한다.

스택(JVM Stack)

메서드 안에서 사용되는 값들(매개변수, 지역변수, return 값 등)이 저장되는 영역으로 메서드 호출 시 생성되는 스레드 수행 정보를 기록한다. 메서드 호출 시 정보들이 LIFO(Last-In First-Out) 방식으로 생성 및 삭제가 진행된다.

네이티브 메서드 스택(Native Method Stack)

자바 외의 언어로 작성된 네이티브 코드를 위한 스택이다. JNI(Java Native Interface)를 통해 호출하는 코드를 수행하기 위한 스택이다.

JVM말고… JRE? JDK?

아주 간단히 말하면.. 포함 관계가 있다. JVM < JRE < JDKJDK가 가장 큰 개념이다. 우리는 모두 JDK를 받기 때문에 JVM을 깔았나 안깔았나 걱정할 필요는 없다.

JRE(Java Runtime Environment)

자바 실행 환경으로 클래스 파일을 실행시키기 위한 환경이다. JVM + 라이브러리를 포함한다.

JDK(Java Development Kit)

자바 통합 개발 환경으로 컴파일러, 디버거를 포함한다. 일반적으로 JDK를 받기에, JVM이 누락되었나 걱정은 안해도 된다.

JRE & JDK

참고

profile
언제나 탐구하고 공부하는 개발자, 주재완입니다.

0개의 댓글

관련 채용 정보