티스토리 뷰

JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가에 대해 알아보겠습니다.

 

 

 

 

JVM(Java Virtual Machine)이란 ?


JVM은 Java Virtual Machine의 약자로써, 직역하면 '가상머신, 자바를 실행하기 위한 가상 기계(컴퓨터)' 라고 할 수 있다. (가상머신이란 프로그램을 실행하기 위해 물리적 머신과 유사한 머신을 소프트웨어적으로 구현한 것이다)

Java는 운영체제(OS)에 종속적이지 않다는 특징을 가지고 있다. 운영체제에 종속받지 않고 실행되기 위해선 운영체제 위에서 Java를 실행시킬 무언가가 필요한데, 그게 바로 JVM이다. 쉽게 말해 윈도우를 사용하던 리눅스를 사용하던 어떤 운영체제를 쓰는지 상관없이 JVM이  설치되어 있다면 JAVA 애플리케이션을 실행할 수 있다.

 

 

컴파일 하는 방법


Java 코드를 JVM에서 바로 실행할 수 있는 것은 아니고, 컴파일 과정을 거쳐야 한다.

JDK를 설치하면 Java Compiler는 javac.exe라는 실행 파일 형태로 설치된다. 정확히는 JDK 의 bin 폴더에 javac.exe 로 존재한다.

Java Complier의 javac 라는 명령어를 사용해 .java 파일을 컴파일하면 .class 파일을 생성할 수 있다. ex. javac <filename>.java

보통은 IDE를 사용하고, build tool등을 사용해서 실제 해당 명령어를 사용해서 컴파일을 하는 경우는 적다.

컴파일 된 코드는 Java Bytecode라고 하며, 컴파일을 수행하면서 문법에 맞지 않을 경우 오류가 발생하는데, 이를 컴파일 에러라고 한다.

 

 

실행하는 방법


java <classname> 명령어로 .class 파일을 실행할 수 있다.  컴파일과정과 마찬가지로 JDK 의 bin 폴더에 java.exe 로 존재한다.  javac는 파일을 가리켜서 컴파일하지만, java는 패키지에 존재하는 클래스를 가리켜서 실행한다는점을 주의해야 한다.

 

 

바이트코드(Bytecode)란?


바이트코드(Bytecode)는 특정 하드웨어가 아닌 가상컴퓨터에서 돌아가는 실행 프로그램을 위한 이진 표현법이다. 하드웨어가 아닌 소프트웨어에 의해 처리되기 때문에, 보통 기계어보다 더 추상적이다.

 

자바 바이트 코드(Java bytecode)는 JVM이 이해할 수 있는 언어로 변환된 자바 소스코드를 의미한다. 자바 컴파일러에 의해 변환된 코드의 명령어 크기가 1바이트라서 자바 바이트 코드라고 불리고 있다.

 

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

 

💡 바이너리 코드란?

바이너리 코드 또는 이진 코드라고 함
컴퓨터가 인식할 수 있는 0과 1로 구성된 이진코드

 

💡 기계어란?

0과 1로 이루어진 바이너리 코드이다.기계어가 이진코드로 이루어졌을 뿐 모든 이진코드가 기계어인 것은 아니다.기계어는 특정한 언어가 아니라 CPU가 이해하는 명령어 집합이며, CPU 제조사마다 기계어가 다를 수 있다.

 

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

 

 

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


전통적인 입장에서 컴퓨터 프로그램을 만드는 방법으로는, 인터프리터 방식컴파일 방식으로 나눌 수 있다.

인터프리터는 컴파일러처럼 고레벨언어를 기계어(저레벨언어)로 해석해주는 번역 프로그램이다. 컴파일러는 전체 소스코드를 보고 명령어를 수집하고 재구성하는 반면 인터프리터는 소스코드의 각 행을 연속적으로 분석하며 실행한다. 때문에 일반적으로 각 행마다 실행하는 인터프리터보다는 컴파일러가 더 빠르다

 

자바스크립트와 파이썬이 대표적인 인터프리터 언어고, C,C++은 컴파일언어, 자바는 컴파일러와 인터프리터 모두 해당된다.

 

JVM으로 다시 돌아와서, 인터프리터는 각 행마다 변환를 해주기 때문에 속도 측면에서 느리다. 이를 개선하기 위하여 도입한 것이 바로 JIT compiler(Just-In-Time Compiler, 이하 JIT 컴파일러) 이다. 

 

인터프리터는 각 행마다 읽어 변환을 하고, JIT 컴파일러는 바이트 코드를 전체를 읽어 한꺼번에 변환을 한다. 매번 코드를 한 줄씩 읽어 변환을 하게 되면, 아무래도 미리 컴파일된 코드를 수행하는 것보다 느릴수 밖에 없다. 그렇다고, 바이트 코드 전체를 프로그램 수행 초기에 모두 컴파일을 하게 되면 초기 속도가 너무 느리게 된다.

 

그렇기 때문에 모든 코드는 초기에 인터프리터에 의해 시작되고, 해당 코드를 충분히 많이 사용할 경우 JIT 컴파일러에서 컴파일을 수행하게 된다. 초기에 인터프리트 방식으로 바이트 코드를 변환하면서 그 코드를 캐싱하여, 같은 함수가 여러 번 불릴 때 매번 코드가 생성되는 것을 방지한다.

 

이렇게 컴파일된 코드를 네이티브 코드 라고 하는데 네이티브 코드는 캐시에 보관되기 때문에 한번 컴파일된 코드는 빠르게 수행될 수 있다.

 

 

JVM의 구성요소


[JVM의 구성요소 ]

JVM은 크게 아래와 같이 이루어져 있다.

 

  • 클래스 로더(Class Loader)
  • 실행 엔진(Execution Engine)
    • 인터프리터(Interpreter)
    • JIT 컴파일러(Just-in-Time)
    • 가비지 콜렉터(Garbage collector)
  • 런타임 데이터 영역 (Runtime Data Area)

 

[ JVM에서의 실행과정 ]

  1. Class Loader를 통해 .class 파일들을 JVM에 올린다
  2. JVM에 있는 .class 파일들을 Execution Engine의 Interpreter와 JIT Complier를 통해 해석된다.
  3. 해석된 바이트 코드는 Runtime Data Areas 에 배치되어 실질적인 수행이 이루어진다

 

[ 클래스 로더(Class Loader)]

자바는 동적 로드, 즉 컴파일 타임이 아니라 런타임(바이트 코드를 실행할 때)에 클래스를 로드하고 링크하는데 이 동적 로드를 담당하는 부분이 JVM의 클래스 로더이다. 정리하자면, 클래스 로더는 런타임 중에 JVM의 메소드 영역에 동적으로 Java 클래스를 로드하는 역할을 한다. 클래스 로더에는 로딩, 링크, 초기화 단계로 나뉘어져 있다.

 

[ 실행엔진(Execution Engine) ]

클래스 로더가 JVM내의 런타임 데이터 영역에 바이트 코드를 배치시키고, 이것은 실행 엔진에 의해 실행된다.

자바 바이트 코드(*.class)는 기계가 바로 수행할 수 있는 언어보다는 비교적 인간이 보기 편한 형태로 기술된 것이다. 그래서 실행 엔진은 바이트 코드를 실제로 JVM 내부에서 기계가 실행할 수 있는 형태로 변경 하며 이는 위에서 설명한 인터프리터 방식과 JIT 컴파일러 방식으로 실행된다.

 

[ 가비지 콜렉터(Garbage collector) ]

유효하지 않는 메모리, 즉 주소를 잃어버려서 사용할 수 없는 메모리를 Garbage라 하는데 Garbage Collector는 메모리가 부족할 때 이런 Garbage를 메모리에서 해제 시켜 다른용도로 사용할 수 있게 해주는 프로그램을 말한다. Garbage Collector를 수행할 땐 Garbage Collector를 수행하는 스레드를 제외한 모든 스레드들이 작업을 멈추고, 이후 완료되면 작업을 다시 시작한다. C, C++는 사용자가 메모리를 직접 해제해주어야 하지만 자바 같은 경우 Garbage Collector가 이 작업을 수행해준다.

 

[ 런타임 데이터 영역 (Runtime Data Area) ]

런타임 데이터 영역은 프로그램을 수행하기 위해 OS로부터 할당받은 메모리 공간이다.

크게 메서드 영역(Method Area), 힙 영역(Heap Area), 스택 영역(Stack Area), PC Register, Native Method Stack로 나눌 수 있다.

 

 

메서드 영역(Method Area) (= Class Area = Static area)

클래스 정보를 처음 메모리 공간에 올릴 때 초기화되는 대상을 저장하기 위한 메모리 공간이며 공유되는 자원이다.

프로그램에서 사용되는 static 변수들을 포함한 래스 수준의 모든 데이터가 저장된다.

 

💡 스태틱 영역에 저장되는 데이터
Field Information (멤버 변수!)
멤버변수의 이름, 데이터 타입, 접근 제어자에 대한 정보

Method Information (메소드!)
메소드의 이름, 리턴타입, 매개변수, 접근 제어자에 대한 정보

Type Information (타입!)
class인지 interface인지의 여부 저장. Type의 속성, 전체 이름, super 클래스의 전체 이름. (interface이거나 object인 경우 제외된다. 이건 Heap에서 관리함)

 

 

힙(heap) 영역

힙(heap) 영역은 자바 프로그램에서 사용되는 모든 클래스 객체(인스턴스) 변수가 저장되는 영역으로, JVM이 관리하는 프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 영역이다. 프로세스 처리를 실행하는 과정에서 동적으로 변화하는 데이터는 기본적으로 여기에 할당된다. 즉, JVM은 자바 프로그램에서 new 연산자를 사용하여 인스턴스가 생성되면, 해당 인스턴스의 정보를 힙 영역에 저장한다. 힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당되며 세 부분으로 나뉘어 진다.

 

Permanent Generation

생성된 객체들의 정보의 주소값이 저장된 공간이다. 클래스 로더에 의해 load되는 Class, Method 등에 대한 Meta 정보가 저장되는 영역이고 JVM에 의해 사용된다. Reflection을 사용하여 동적으로 클래스가 로딩되는 경우에 사용된다.

 

💡 Reflection이란?
객체를 통해 클래스의 정보를 분석해 내는 프로그래밍 기법
구체적인 클래스 타입을 알지 못해도, 컴파일된 바이트 코드를 통해
역으로 클래스의 정보를 알아내어 사용할 수 있다는 뜻이다.

 

 

 New/Young 영역

이곳의 인스턴스들은 추후 가비지 콜렉터에 의해 사라진다. 생명 주기가 짧은 “젊은 객체”를 GC 대상으로 하는 영역이다.

여기서 일어나는 가비지 콜렉트를 Minor GC 라고 한다.

 

  •  Eden: 객체들이 최초로 생성되는 공간
  • Survivor 0, 1: Eden에서 참조되는 객체들이 저장되는 공간
💡 Eden 영역에 객체가 가득차게되면 첫번째 가비지 콜렉트가 발생한다.
Eden영역에 있는 값등릉 Survivor 1 영역에 복사하고 이 영역을 제외한 나머지 객체를 삭제한다.

 

 

Old 영역

이곳의 인스턴스들도 마찬가지로 추후 가비지 콜렉터에 의해 사라진다. 생명 주기가 긴 “오래된 객체”를 GC 대상으로 하는 영역이다.
여기서 일어나는 가비지 콜렉트를 Major GC 라고 한다. Minor GC에 비해 속도가 느리다. New/Young Area에서 일정시간 참조되고 있는, 살아남은 객체들이 저장되는 공간이다.

 

 

JVM 스택 영역

프로그램 실행과정에서 임시로 할당되었다가 메소드를 빠져나가면 바로 소멸되는 특성의 데이터를 저장하기 위한 영역이다.

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

 

PC Register

Thread가 시작될 때 생성되며 생성될 때마다 생성되는 공간으로, 스레드마다 하나씩 존재한다.

Thread가 어떤 부분을 어떤 명령으로 실행해야할 지에 대한 기록을 하는 부분으로 현재 수행 중인 JVM 명령의 주소를 갖는다.

 

Native method stack

자바 프로그램이 컴파일되어 생성되는 바이트 코드가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역이다.

JAVA가 아닌 다른 언어로 작성된 코드를 위한 공간이며 Java Native Interface를 통해 바이트 코드로 전환하여 저장하게 된다.

 

 

JDK와 JRE의 차이


[ JDK(Java Development Kit) ]

Java 를 사용하기 위해 필요한 모든 기능을 갖춘 Java용 SDK (Software Development Kit)이다.

JDK 는 JRE를 포함하고 있으며, JRE에 있는 모든 것 뿐만 아니라 컴파일러(javac)와 jdb, javadoc 과 같은 도구도 있다.

즉, JDK는 프로그램을 생성, 실행, 컴파일 할 수 있다.

 

 

[ JRE(Java Runtime Environment) ]

JVM + 자바 클래스 라이브러리(Java Class Library) 등으로 구성되어 있다. 컴파일 된 Java 프로그램을 실행하는데 필요한 패키지이다.

 

요약
JDK는 자바 프로그램을 실행, 컴파일, 개발용 도구.
JRE, JVM를 모두 포함하는 포괄적이 키트이다.
JRE는 자바 프로그램을 실행할 수 있게 하는 도구이다. JVM을 포함하고 있다.

 

 

 

 

 

 

참고

 

[Java] 자바의 동작과정 Java Compiler와 JVM

이클립스에서 *.java를 단축키 눌러서 실행시킬 줄만 알았지 *.java 파일이 어떠한 과정을 거쳐 실행이 되는지는 알지 못했습니다. 따라서 자바 컴파일러는 어떤 역할을 수행하며, 어디서 많이 들

kingofbackend.tistory.com

 

[JAVA] JVM이란? 개념 및 구조 (JDK, JRE, JIT, 가비지 콜렉터...)

JVM이란 무엇인가 Java Virtual Machine의 줄임말. 직역하면 '자바를 실행하기 위한 가상 기계(컴퓨터)'라고 할 수 있다. Java 는 OS에 종속적이지 않다는 특징을 가지고 있다. OS에 종속받지 않고 실행되

doozi0316.tistory.com

 

백기선님 온라인 스터디 1주차 - JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.

1주차!

velog.io

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함