본문 바로가기
공부/스터디할래? with.백기선

1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가?

by Moonsc 2020. 11. 14.
728x90

github.com/whiteship/live-study/issues/1

 

1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가. · Issue #1 · whiteship/live-study

목표 자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기. 학습할 것 JVM이란 무엇인가 컴파일 하는 방법 실행하는 방법 바이트코드란 무엇인가 JIT 컴파일러란 무엇이며 어떻게 동작하는지 JV

github.com

 

목표

자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기.

 

과제

 

JVM이란 무엇인가 

  • Java Virtual Machine 이하 JVM은 자바 바이트코드(java bytecode)를 플랫폼(OS)에 독립적일 수 있도록 해석하는 역할을 맡는다.
  • 프로그램 메모리를 관리하며, 최적화한다.

 

컴파일 하는 방법

javac 명령어를 통해  .java (소스코드) 파일 을 .class (바이트 코드) 파일로 컴파일 할 수 있다.

 

.java vs .class

  • .java 파일은 java 규칙에 맞게 작성한 소스코드(for Human) 파일을 말한다. 
  • .class 파일은 컴파일러에 의해 생성된 자바 바이트코드(for JVM) 파일이다. 

 

자바 컴파일러 특징

1. .java 파일에 오류가 있는지 검사한다.

2. 기계어로 변환하지 않고 for JVM 바이트코드(.class)를 생성한다.

  • Java의 특징 중 플랫폼에 독립적으로 실행 가능한 환경을 제공할 수 있는 이유이다.

 

 

실행하는 방법

  1. 소스코드를 작성한다. 
  2. 컴파일러를 통해 바이코드를 생성한다. (javac)
  3. 컴파일된 바이트코드를 호출한다. (java 바이트코드파일)

 

바이트코드란 무엇인가

자바 바이트코드(Java bytecode)는 자바 가상 머신이 실행하는 명령어의 형태이다. 각각의 바이트코드는 1바이트로 구성되지만 몇 개의 파라미터가 사용되는 경우가 있어 총 몇 바이트로 구성되는 경우가 있다. 256개의 명령코드 모두가 사용되지는 않는다.

출처: 위키백과 ko.wikipedia.org/wiki/자바_바이트코드

 

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

컴퓨터 과학 프로그래밍 언어에서 사용하는 용어. C C++에서 하는 것처럼 프로그램을 실행하기 전에 처음 한 번 컴파일하는 대신, 프로그램을 실행하는 시점에서 필요한 부분을 즉석으로 컴파일하는 방식을 말한다.

보통 인터프리터 방식의 언어 구현들이 성능 향상을 목적으로 도입하는 경우가 많은데, JIT 컴파일러는 같은 코드를 매번 해석하는 대신 처음 실행될 때 인터프리트를 하면서 자주 쓰이는 코드를 캐싱한 뒤[2], 이후에는 캐싱된 코드를 가져다 쓰기 때문에 인터프리터의 느린 실행 속도를 개선할 수 있다. 따라서 사실 JIT '컴파일러'보다는 JIT '인터프리터'가 더 정확한 표현이다. 바이트코드 컴파일을 사용하는 Java도 바이트코드를 기계어로 번역할 때 JIT 컴파일러를 사용한다.

단점이라면 초기 구동 시에는 소스 코드(혹은 바이트코드)를 실행 단계에서 컴파일하는 데에 시간과 메모리를 소모하기 때문에 정적 컴파일된 프로그램에 비해 실행 속도 면에서 손해를 본다는 것으로, 특히 실행 시간이 매우 짧은 경우에는 애써 컴파일된 코드를 제대로 울궈먹기도 전에 프로그램이 끝나는 배보다 배꼽이 더 큰 상황이 벌어지기도 한다.[3]

크게 나눠서 HotSpot VM과 같이 메소드(함수) 단위로 JIT 컴파일을 하는 방식과, 그보다 더 작은 단위에서 프로그램 실행 흐름을 실시간으로 추적하며 컴파일할 코드를 탐색하는 Tracing JIT 방식으로 분류할 수 있다. 특히 Tracing JIT의 경우에는 실행 시점에만 알 수 있는 정보를 컴파일에 적극적으로 반영[4]하기 때문에 이론적으로는 정적 컴파일 방식보다 컴파일 속도가 더 빨라질 수도 있다.

미리 컴파일된 코드를 실행하는 것이 아닌, 런타임에 동적으로 코드를 생성하여 실행한다는 특징 때문에 JIT 컴파일러는 잠재적으로 상당한 보안 문제를 가지고 있다. 특히 JIT 컴파일러 자체에 버그가 있는 경우 곧바로 보안취약점이 되는 경우가 많다. 대표적으로 인텔 CPU게이트로 유명한 스펙터 보안취약점은 JIT에 의존하는 JavaScript 엔진을 가진 브라우저에서만 발생했다. 오라클의 HotSpot VM 또한 JIT 컴파일러 버그로 인한 다수의 보안취약점이 있었다.

참고로 iOS에서는 상기한 보안문제를 이유로 네트워크로 바이너리나 코드를 다운받아 실행하는 것을 금지하고 있다. 구글 크롬이나 파이어폭스의 iOS 버전이 자체 엔진을 쓰지 못하고 애플이 제공하는 WebKit의 웹뷰를 사용할 수밖에 없는 주요 이유 중 하나다.[5] 요즘 브라우저들은 JavaScript 엔진으로 JIT를 쓰기 때문.
iOS도 편법으로 구현이 가능하나 정책이 이를 허용하지 않아 스토어에 올릴때 reject된다

- 출처 : 나무위키  namu.wiki/w/JIT

 

 

JVM 구성 요소

출처: https://medium.com/webeveloper/jvm-java-virtual-machine-architecture-94b914e93d86

 

Class Loader (클래스 로더)

바이트코드 클래스 파일을 런타임 시에 동적으로 로드한다.

읽은 바이트코드를 Runtime Data Areas 에 배치시키는 역할을 맡는다.

 

Excution Engine (실행 엔진)

Class Loader가 JVM 내의 Runtime Data Areas에 배치한 바이트코드를 Excution Engine에 의해 실행시킨다.

 

인터프리터

바이트코드를 읽고 기계어 코드(Native Code)로 해석하여 순차적(한줄 씩)으로 실행한다.

이러한 방식은 매우 비효율적으로 보일 수 있겠지만, 가상 머신에서 돌아가는 바이트 코드들은 매우 저수준의 인터프리터 언어이기에 생각보다 큰 노력이 필요치 않는다. 

그럼에도 인터프리터의 문제는 매번 동일한 방법을 여러번 해석하여 시스템 성능을 저하 시킨다. 이 문제를 극복하기 위해 JIT 컴파일러가 도입되었다.

 

JIT (Just In Time)

JIT 컴파일러는 느린 실행이라는 인터프리터의 단점을 보완하고 성능을 향상시킨 컴파일러다. 뜻과 같이 그 순간 컴파일 되기에 반복되는 내용을 컴파일을 해서 사용하곤 한다. 

JIT 컴파일링은 실행될 때 최초 실행되기 때문에, 최초 실행에서는 조금 느릴 수 있지만, 반복적인 작업을 할 때 훨씬 높은 성능을 보여준다.

 

Garbage Collector (쓰레기 수집)

메모리를 자동으로 관리하는 자바 프로그램이다. 데몬 스레드에서 항상 백그라운드로 실행되며, 기본적으로 Heap 영역의 메모리를 JVM이 판단해 더 이상 사용되지 않는 인스턴스는 자동으로 할당 된 메모리를 삭제하는 역할을 해준다.

 

Runtime Data Areas (런타임 데이터 영역)

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

 

Method Area

클래스 멤버 변수의 이름, 데이터 타입, 리턴 타입, 상수풀, static 변수 등이 저장된다. 클래스 수준의 정보가 저장되는 곳이며, 저장된 정보들은 공유된다.

 

Heap Area

new 연산자로 생성된 객체 또는 배열이 저장된다. 아래서 생성된 member는 Stack Area에 저장되며 new 연산자로 생성된 Member는 Heap Area에 저장된다.

Member member = new Member();

 

Stack Area

스레드가 생성될 때 마다 생성되는 영역으로, 대표적으로 지역변수가 여기 저장된다. 메소드를 호출할 때마다 스택이 개별적으로 생성되기 때문에 동시성 문제를 해결하기 위해서 메소드에 동기화 블럭을 지정하는데, 동기화 블럭 없이 동시성 문제를 해결하는 방법 중 하나가 지역 변수를 사용하는 방법이다.

 

PC Register

쓰레드가 생성될 때마다 생성되는 영역으로 Program Counter 즉, 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역이다.

이것을 이용해서 쓰레드가 돌아가면서 수행할 수 있게 한다. 쓰레드가 생성되었을 때 Method Area 와 Heap Area는 모든 스레드가 공유하며, PC Regiter, Stack Area, Native Stack Area는 공유되지 않는다.

 

Native Method Stack

자바 언어 이외의 언어로 작성된 코드를 저장하는 메모리 영역이며 주로 native 키워드가 붙은 애들이 저장된다.

 

 

JDK와 JRE의 차이

출처 : https://docs.oracle.com/javase/8/docs/index.html

 

Java Tool & Tool APIs  + Java Language + JRE = JDK이다.

 

References.

댓글