JVM이란?(Java Virtual Machine)

자바프로그램과 운영체제 사이에서 중개자 역할을 수행하는데 자바가 운영체제 종류에 상관없이 프로그램을 실행할수있게 도와줍니다. 

 

(왼) Java프로그램 실행 구조

 

 

자바 컴파일러에 의해 .java -> .class(바이트 코드)로 변환하고 이러한 바이트 코드를 JVM에서 읽어 복잡한 과정을 거쳐 운영체제 종류에 상관없이 프로그램을 실행할수있게 해줍니다.

 

만약에 .java를 Window에서 만들었고 Mac에서 실행하고 싶으면 Mac용 JVM을 통해 실행이 가능합니다.

JVM은 이처럼 종속적이라는 특성이있습니다. 

 

 

JVM 메모리 구조(Run Time Data Areas)

JVM의 메모리구조를 자세히 알아보겠습니다.

크게 Garbage Collector, Excution Engine, Class Loader, Runtime data Area 4가지로 나눌수있다. 

 

 

 

Class Loader에서 클래스파일인 바이트코드를 로드하고 Run time Data Area로 적재하는 역할을 한다. 

 

Execution Engine에서 Class Loader에 의해 RunTime Data Area에 적재된 바이트코드들을 기계어로 변경해 명령어 단위로 실행하는 역할을 해준다. 이때 명령어를 하나하나 실행하는 인터프리터 방식과 JIT(Just-In-time) 컴파일 방식이있다. 

인터프리터 방식은 한줄한줄해석해서 실행하므로 속도가 느리다는 단점이있고 이를 해결하기위해 JIT 컴파일 방식이다.

Java는 JIT 컴파일 방식으로 JIT 컴파일러를 통해 바이트 코드를 실행하는 시점에 각 OS에 맞게 네이티브 코드로 변환하여 실행해 속도가 빠르다.

하지만 바이트 코드 -> 네이티브 코드로 변환하는데 비용이 소모되고 JVM은 모든 코드를 JIT 컴파일 방식으로 실행되지않고 인터프리터 방식을 사용하다가 일정 기준이 넘으면 JIT 컴파일 방식으로 명령어를 실행한다. 

 

Garbage Collector는 Garbage Collection을 실행하는 주체를 의미한다. 

- 여기서 GC(Garbage Collection)란? 

Garbage란 쓰레기란 의미로 불필요한 메모리를 의미한다. 

C언어를 쓰다보면 free 라는 함수를 통해 메모리를 동적으로 해제해 주어야한다.

하지만 Java에서는 JVM GC 해당 인스턴스를 가리키는 참조값이 없으면 접근할수없고 메모리에 남아만있기때문에 메모리에서 해제를 해줍니다.

 

- 용어정리) Garbage Collection과 Garbage Collector 차이

Garbage Collection은 메모리 관리를 위해 사용되는 개념. 

Garbage Collector는 위에것을 실제 수행하는 주체. 

 

Runtime Data Areas

Runtime Data 영역이라 부르는데 크게 5개의 영역으로 나뉩니다.

각 쓰레드별로 pc Register, stack, native method stack 영역이 있고 

전체 쓰레드 공유하는 Heap, method 영역이 있습니다.

 

각 쓰레드별 생성되는 데이터 영역

pc Register, stack, native method stack 영역 쓰레드 별로 독립적으로 갖고있고 

쓰레드가 실행될때 생성되며 쓰레드가 종료되면 해제됩니다.

 

전체 쓰레드가 공유하는 데이터영역

Heap이나 Method영역은 각 쓰레드가 서로 공유하고 

JVM 시작될떄 생성되며 JVM 종료되면 해제됩니다.

 

1. PC Register(Program Counter Register)

CPU의 Register와 역할이 비슷한데 현재 수행중인 JVM 명령의 주소값이 저장된다. 

2. JVM Stack

각각의 쓰레드는 생성되면서 동시에 하나의 스택영역만 생성된다. (예를들어 3개의 쓰레드를 사용하면 각 쓰레드별로 하나의 스택영역이 생성되어 총 3개가 생성된다.) 스택은 Stack Frame이라는 구조체를 저장하며 이는 지역변수, 메서드호출 또는 반환을 저장합니다.

Stack Frame 메서드를 호출할떄마다 Frame push하고 메서드가 종료되면 프레임을 제거하는 pop 수행합니다

 

- 쓰레드마다 스택을 독립적으로 할당하는 이유는?

한 순간에 하나의 쓰레드만 실행이 가능한데  각 쓰레드안에 스택영역이  독립적인 이유는 독립적인 함수 호출이 가능하게하여 독립적인 실행 흐름을 가능하게 하기위해서이다. 

 

- 프로그램 -> 프로세스 -> 쓰레드

(프로그램 -> 프로세스)

프로그램은 어떤 작업을 실행할수있는 파일로 저장장치에 저장되어있지만 실행전 메모리에 올라가지 않은 정적인 상태이며 보조기억장치에 존재한다. 실행되는 명령어가 입력되면 그때 메모리에 올라간다. 이때 정적상태에서 동적인 상태가 되는데 이 상태를 프로세스라 합니다.

즉, 프로세스는 프로그램이 메모리에 올라와 있는 상태를 의미합니다.

 

(프로세스 -> 쓰레드)

과거에는 프로그램을 하나의 프로세스만 사용했지만 음악듣거나 코딩하거나 등 여러 동작을 하고싶어 하나의 프로그램에서 여러개의 프로세스를 만들고싶어했습니다.하지만 이는 불가능했습니다. 왜냐하면 OS 는 안정성을 위해 프로세스마다 자신에 할당된 메모리 안의 정보만 접근할수있게 제약을 두었고 벗어나면 오류를 발생하기떄문이다.

그래서 프로세스보다 더 작은 실행단위인 쓰레드란 개념이 나왔습니다.

 

3. native Method Stack

자바 언어로 작성된 C C++같은 네이티브 코드의 메서드를 호출하고 수행하기위한 스택영역이다. 

4. Method 영역

Class Loader가 적재한 클래스에대한 메타데이터를 저장하는 공간이며 프로그램의 모든영역에서 공통의 데이터를 공유합니다. 

주로 클래스(클래스의 실행코드인 바이트코드),인터페이스,정적변수, 상수 를 저장합니다.

그리고 내부에 Runtime Constant Pool 이라는 영역이 존재해 모든 Constant 레퍼런스를 저장한다. 

5. Heap 영역

클래스의 인스턴스나 배열을 생성하면 할당되는 영역입니다. 

할당된 객체(인스턴스나 배열)는 직접 해제가 불가능하여 오직 GC(가비지 컬렉터)에 의해 자동으로 메모리에서 해제됩니다.

 
 
 
 
 
 
 
 

 

 
 
 
 
 
 

'𝗝𝐀𝗩𝐀' 카테고리의 다른 글

코딩테스트 문제요령  (0) 2023.12.22