brunch

You can make anything
by writing

C.S.Lewis

by 이재린 Jan 24. 2021

JVM은 무엇이며 자바 코드는
어떻게 실행하는 것인가

백기선 스터디 1주 차

JVM이란 무엇인가

- JVM(Java Virtual Machine, 자바 가상 머신) 은 High Level 언어로 작성된 Java 프로그램을 해석하고
실행시키는, 일종의 가상 운영체제이다.

컴파일 과정을 통해 High Level과 Low Level의 중간 단계인 Byte Code 로 변환 한 뒤,
변환된 내용(Byte Code)을 읽어들임으로써 프로그램이 수행되는 구조를 가지고 있다. 

JVM의 설치가 가능 하다면 OS 구분없이 동일하게 동작을 할 수 있다는 장점을 가지고 있다.


컴파일 하는 방법

- 컴파일이란? 작성한 프로그램을 실행 시키기 위해서는 컴퓨터가 이해할 수 있는 0과 1로만 이루어진 데이터로 변환 하는 과정


(Linux Centos7, Java8 에서 실행 하였습니다.)


1. java 파일 생성


2. 생성된 파일 확인


3. javac ${target.java} 명령어 실행


4. Main.class 파일 생성 확인


실행하는 방법

- 위 작업의 결과물인 .class 파일을 JVM을 통해 수행한다.

java ${target} 명령어 실행


바이트코드란 무엇인가

- 바이트 코드(bytecode)란 자바 가상 머신이 인식 가능한  Low-level 언어로,
자바로 작성된 소스 코드의 빌드 결과물을 의미합니다.

자바 컴파일러(javac)에 의해 변환되고, 각 명령어 크기가 1바이트라서 자바 바이트 코드라 불립니다.

자바 바이트 코드의 확장자는 .class이며,

자바 가상 머신(JVM)만 설치되어 있으면, 어떤 운영체제에서라도 실행 가능합니다.


JIT 컴파일러란 무엇이며 어떻게 동작하는지

- 우선 프로그래밍 언어의 실행 방식 두 가지에 대한 이해가 필요하다.

1. 컴파일 방식 : 소스코드를 한번에 읽을 수 있도록 변환된 Native Machine Code(기계어)를 실행하는 방식.

실행 속도는 빠르지만, 빌드에 시간이 소요된다.

(ex. C/C++)

2. 인터프리터 방식 : 런타임(실행 시점)에 한줄씩 읽어 들이면서 프로그램을 실행하는 방식

실행 속도는 느리지만, 빌드 시간이 없다.

(ex. Python)


위 방법에는 각각 장/단점이 있는데, Java는 위의 두 가지 방식을 모두 사용한다.

컴파일 결과물인 바이트 코드를 JVM이 읽어들인 뒤, 기계어로 해석하여 프로그램이 실행되는데

이때 JIT(Just-In-Time) 컴파일러가 사용되며 인터프리터 방식의 단점을 보완한다.


복잡하고 다양한 연산을 하면서 반복적으로 호출되는 메서드들을 JIT의 코드 캐시(Code Cache)에 저장하기
때문에 더 빠르게 호출하여 성능 향상에 도움이 된다.(이를 JIT 컴파일링 이라 한다.)


다만, JIT 컴파일러가 언제나 프로그램의 성능을 향상 시켜주는 것은 아니기 때문에,
사용 여부는 사용자가 직접 선택을 할 수 있다.


JVM 구성 요소

JVM은 크게 4가지로 구성 되어 있다.


1. Class Loader

- JVM 으로 클래스 파일들을 load하고, link를 수행하는 모듈로 Runtime 시점에 동적으로 클래스를 로드한다. 

자바는 동적 코드, 컴파일 타임이 아니라 런타임에 코드를 참조 하는 특성이 있기 대문에.
클래스를 처음으로 참조할 때 해당 클래스를 load하고 link한다. (Interpreter 언어의 특성)


2. Execution Engine

- class loader를 통해 배치된 클래스를 실행시킨다.

클래스 파일(바이트 코드)은 비교적 인간이 보기 쉬운 형태이기 때문에 기계가 실행할 수 있는 형태로 변경시키는데

이 때, 두 가지 방식을 사용한다. ( 인터프리터, JIT ) 


3. Runtime Data Area

- JVM이 운영체제 위에서 실행될 때 할당받는 메모리 영역이다.

  Method Area : 클래스영역 이라고도 한다. Interface, Class, Method, Field 등의 모든 정보가 들어 있다. 변수 명, 반환 타입, 인자의 개수, 인자 타입 등등 시그니처 정보, 접근제어자도 포함된다.
이 영역은 JVM내에서 실행중인 모든 쓰레드들이 공유한다. 또한, new를 통해 동적으로 생성할 때 저장되므로 GC의 대상이다.

  Heap : 런타임에 생성된 인스턴스들이 위치한 곳이다. 대표적인 GC처리 대상이며, 왜 Heap에 저장하는지는 힙정렬과 관련이 있다. 사용빈도가 높은 인스턴스를 맨 위(루트노드)로 올리고, 캐시 히트율을 올리는 방식이다. JVM내의 모든 쓰레드들이 공유한다.

  JVM Stacks : 호출스택(Call Stack)이라고도 불린다. 메소드 단위의 실행에 필요한 공간을 제공한다.
메소드의 매개변수, 지역변수 등 임시적인 데이터를 저장한다. 원시 타입은 스택에 값이 직접 저장 되고, 레퍼런스 타입은 스택에 인스턴스가 위치한 힙의 주소를 쓴다. 메소드가 끝나면 메모리공간은 반환되며, 쓰레드마다 1개씩 독립적인 공간을 갖는다.

  PC Registers : Java는 C언어와 달리 Stack Based 언어이다. CPU의 레지스터를 조작하기 위한 명령어(Instruction, MOV, ADD 등등).
그러나 Java 에서는 플랫폼에 독립적으로 동작 하기 위해 이러한 PC Registers 라는 일종의 스택을 이용해 동작한다.

  Native Method Stacks : 자바 외 언어로 작성된 코드를 위한 스택이다. JNI(Java Native Interface)를 통해 호출한다.


4. Garbage Collector

- 힙 영역에 생성된 객체들 중에 참조되지 않는 객체들을 메모리에서 제거하는 역할을 하며, 가비지 컬렉터가 역할을 하는 시간은 정확히 언제인지를 알 수 없다. (참조가 없어지자마자 해제되는 것을 보장하지 않음) 또 다른 특징은 가비지 컬렉터가 수행되는 동안 가비지 컬렉터를 수행하는 쓰레드가 아닌 다른 모든 쓰레드가 일시정지 된다.


JDK와 JRE의 차이

JDK(Java Development Kit)

- 자바 개발 도구. 자바를 통해 프로그램을 개발할때 사용되는 모듈(라이브러리)들이 포함된 설치 버전이다.

기본적으로 자바 프로그램을 실행하기 위한 JRE를 포함하고 있으며, 그외에 빌드 디버깅에 필요한 모듈을 보유하고 있다.


JRE(Java Runtime Environment)

- 자바 실행 환경. 자바로 작성/빌드 된 프로그램을 실행시키기 위한 모듈이 모여있는 설치 버전으로,

자바 프로그램의 실행을 위한 최소단위의 모듈이다.

작가의 이전글 가장 좋아하는 음식
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari