JVM(Java Virtual Machine)

작성일

JVM(Java Virtual Machine)이란?

직역하면 자바를 실행하기 위한 가상 기계(컴퓨터)

자바 프로그램이 어느 기기나 운영체제 상에서도 실행될 수 있도록 하면서 프로그램 메모리를 관리하고 최적화하는 것

자바프로그램 실행과정

Untitled

원시코드(*.java)는 CPU가 인식하지 못하므로 기계어로 컴파일을 해줘야함.

원시코드(.java)는 JVM이 인식할 수 있는 Java Bytecode(.class)로 변환됨. (Java compiler가 변환해줌)

참고 Java compiler란?
JDK를 설치하면 bin에 존재하는 javac.exe를 말함 (즉, JDK에 Java compiler가 포함되어 있음) javac 명령어를 통해 .java를 .class로 컴파일 할 수 있음

변환된 bytecode는 기계어가 아니기 때문에 OS에서 바로 실행되지 않음.

이때, JVM이 OS가 bytecode를 이해할 수 있도록 해석해준다. 따라서, Byte Code는 JVM 위에서 OS 상관없이 실행될 수 있는 것.

OS에 종속적이지 않고, Java 파일 하나만 만들면 어느 디바이스든 JVM 위에서 실행할 수 있음.

컴파일 하는 방법

Java Compiler는 JDK를 설치하면 javac.exe라는 실행 파일 형태로 설치됨. (경로: *jdk/bin/javac.exe)

Java Compiler의 javac라는 명령어를 사용하면 .class파일을 생성할 수 있음.

javac test.java

실행하는 방법

java 명령어로 .class 파일을 실행 시킬 수 있음.

java test(.class 파일 이름)

참고
JDK 디렉토리의 /bin 폴더에 존재하는 java.exe는 JVM을 구동시키기 위한 명령 프로그램(JRE) java 명령어로 JVM을 실행 시킬 수 있음

바이트 코드란?

가상 컴퓨터(VM)에서 돌아가는 실행 프로그램을 위한 이진 표현법

자바 바이트코드는 JVM이 이해할 수 있는 언어로 변환된 자바 소스코드를 의미함

바이트 코드는 다시 실시간 번역기 or JLT 컴파일러에 의해 바이너리 코드로 변환된다.

즉, CPU가 이해하는 언어는 바이너리 코드, 가상 머신이 이해하는 코드는 바이트 코드

지금까지 내용을 정리하면,

자바 코드를 컴파일하여 .class 바이트 코드로 만들면 이 코드가 자바 가상 머신 환경에서 실행 됨. JVM은 자바 실행 환경 JRE에 포함되어 있음. 현재 사용하는 컴퓨터의 운영체제에 맞는 자바 실행환경(JRE, Java Runtime Environment)가 설치되어 있다면 자바 가상 머신이 설치되어 있다는 뜻

Untitled2

Java는 컴파일된 바이트 코드로 어떤 JVM에서도 동작시킬 수 있기 때문에 플랫폼에 의존적이지 않지만, JVM은 플랫폼에 의존적. 즉, 리눅스 JVM과 윈도우의 JVM은 서로 다르다.

바이트 코드를 읽는 방식

JVM은 바이트코드를 명령어 단위로 읽어서 해석하는데, Interpreter 방식JIT 컴파일 방식 두가지 방식을 혼합해서 사용함.

Interpreter 방식은 바이트코드를 한 줄씩 해석, 실행하는 방식이며 초기 방식으로 속도가 느리다는 단점이 있다. 이를 보완하기 위해 나온 것이 JIT(Just In Time) 컴파일 방식.

JIT(Just In Time) 컴파일 방식은 바이트코드를 JIT 컴파일러를 이용해 프로그램을 실제 실행하는 시점에 각 OS에 맞는 Native Code로 변환하여 실행 속도를 개선함. 하지만, 바이트코드를 Native Code로 변환하는 데에도 비용이 소요되므로, JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고, 인터프리터 방식을 사용하다가 일정 기준이 넘어가면 JIT 컴파일 방식으로 명령어를 실행함.

JIT 컴파일러란?

JIT 컴파일러는 바이트 코드를 읽는 방식 중 하나인 인터프리터 방식의 속도가 느리다는 점을 보완한 방식. 같은 코드를 매번 해석하지 않고, 실행할 때 컴파일을 하면서 해당 코드를 캐싱해버림. 이후에는 바뀐 부분만 컴파일하고, 나머지는 캐싱된 코드를 사용함.

자바에선 자바 컴파일러가 자바 프로그램 코드를 바이트 코드로 변환한 다음, 실제 바이트 코드를 실행하는 시점에서 자바 가상 머신(JVM, 정확히는 JRE)이 바이트 코드를 JIT 컴파일을 통해 기계어로 변환

가비지 컬렉션 (Garbage Collection, GC)

JRE의 구성 요소 중 하나. 자바 이전에는 프로그래머가 모든 프로그램 메모리를 관리했지만 Java에서는 JVM이 프로그램 메모리를 관리함. 더 이상 사용되지 않는 인스턴스를 찾아 메모리에서 삭제함

참고 JDK와 JRE 차이?
JDK(Java Development kit, 자바 개발 키트)
자바를 사용하기 위해 필요한 모든 기능을 갖춘 Java용 SDK(Software Development Kit). JDK는 JRE를 포함하고 있다. 즉, JDK는 프로그램을 생성, 실행, 컴파일 할 수 있음
JRE(Java Runtime Environment, 자바 런타임 환경)
JVM + 자바 클래스 라이브러리 등으로 구성되어 있으며, 컴파일 된 Java 프로그램을 실행하는데 필요한 패키지

JVM의 메모리 구조

위의 내용을 다시 정리하자면, JVM이란 Java Virtual Machine의 약자로, 자바 가상 머신이라고 부름. 자바와 운영체제 사이에서 중개자 역할을 수행하며, 자바가 운영체제에 구애 받지 않고 프로그램을 실행할 수 있도록 도와준다. 또한, 가비지 컬렉터(GC)를 사용한 메모리 관리도 자동으로 수행하며, 다른 하드웨어와 다르게 레지스터 기반이 아닌 스택 기반으로 동작함.

JVM의 구조

  • Garbage Collector
  • Execution Engine
  • Class Loader
  • Runtime Data Area

Untitled3

자바 소스 파일은 자바 컴파일러에 의해서 바이트 코드 형태인 클래스 파일이 되고 이 클래스 파일은 클래스 로더가 읽어들이면서 JVM이 수행됨

Class Loader

.java 소스를 자바컴파일러가 컴파일하면 .class(바이트코드)이 생성되는데 이렇게 생성된 클래스파일들을 엮어서 JVM이 운영체제로부터 할당받은 메모리영역인 Runtime Data Area로 적재하는 역할을 Class Loader가 함. (자바 애플리케이션이 실행중일 때 이런 작업 수행)

Execution Engine

클래스 로더를 통해 JVM 내에 Runtime Data Area에 배치된 바이트 코드들을 기계어로 변경해 명령어 단위로 읽어서 실행하는 역할을 한다.

최초 JVM이 나왔을 당시에는 인터프리터 방식이었기때문에 속도가 느리다는 단점이 있었다. 하지만 이를 JIT 컴파일러 방식을 통해 보완함. JIT는 바이트 코드를 어셈블러 같은 네이티브 코드로 바꿈으로써 실행이 빠르지만 변환하는데 비용이 발생함. 이 같은 이유로 JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고, 인터프리터 방식을 사용하다가 일정한 기준이 넘어가면 JIT 컴파일러 방식으로 실행함

Garbage Collector(GC)

GC는 힙 메모리 영역에 생성된 객체들 중에서 참조되지 않은 객체들을 탐색 후 제거하는 역할을 한다.

GC가 역할을 하는 시간은 언제인지 정확히 알 수 없다. (참조가 없어지자마자 해제되는 것을 보장하지 않음)

Runtime Data Area

JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역. 이 영역은 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack로 나눌 수 있음.

  • Method Area

    모든 쓰레드가 공유하는 메모리 영역. 메소드 영역은 클래스, 인터페이스, 메소드, 필드, Static 변수 등이 생성되는 영역.

  • Heap Area

    모든 쓰레드가 공유하며, new 키워드로 생성된 객체와 배열이 생성되는 영역. 또한, 메소드 영역에 로드된 클래스만 생성이 가능하고 Garbage Collector가 참조되지 않는 메모리를 확인하고 제거하는 영역.

  • Stack Area

    Untitled4

    메서드 호출 시마다 각각의 스택 프레임(그 메서드만을 위한 공간)이 생성한다. 메서드 안에서 사용되는 값들을 저장하고, 호출된 메서드의 매개변수, 지역변수, 리턴 값 및 연산 시 일어나는 값들을 임시로 저장함. 마지막으로, 메서드 수행이 끝나면 프레임별로 삭제한다.

  • PC Register

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

  • Native Method Stack

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

쓰레드가 생성되었을 때 기준으로1,2번인 메소드 영역과 힙 영역을 모든 쓰레드가 공유하고,3,4,5번인 스택 영역과 PC 레지스터, Native method stack은 각각의 쓰레드마다 생성되고 공유되지 않는다.

카테고리: