web developer

[java] JVM에서 java 코드를 실행하는 방법 (JIT 컴파일러) 본문

Language/Java

[java] JVM에서 java 코드를 실행하는 방법 (JIT 컴파일러)

trueman 2022. 9. 7. 00:30
728x90
728x90

JVM에서 java 코드를 실행하는 방법


JVM은 바이트 코드(Byte Code)라 불리는 기계어 코드를 실행하는 가상 머신이다.

 

우리가 Java로 작성한 코드들은 Compile time에(소스파일(*.java)이 목적파일(*.class)로 변환될때) 바이트 코드로 변환되며,

바이트 코드들은 Run time에 기계어로 변환되어 기계어가 JVM 상에서 실행된다.

 

JVM에서 java 코드를 실행하는 방법

즉, Java 코드는 프로그램 실행 시점 전인 컴파일 타임에 바이트 코드로 변환이 모두 완료되지만 JVM에서 바이트 코드를 실행하기 위해서는 바이트 코드를 기계어로 변환하는 단계를 하나 더 거쳐야 한다.

 

이때 JVM에서 바이트 코드들을 기계어로 번역하는 컴파일러가 바로 JIT 컴파일러이다.


정적 컴파일과 동적 컴파일의 한계점과 장점


컴파일러에서 프로그램 코드를 기계어로 변환할 수 있는 시점은 2가지가 있다. 하나는 프로그램 실행 전이고, 다른 하나는 프로그램 실행 중 이다. 실행 시점 전에 기계어로 변환하는 컴파일러를 정적 컴파일러라 하고, 실행 중 기계어로 변환하는 컴파일러를 동적 컴파일러(인터프리트 언어)라 한다.

 

C, C++와  같이 실행 시점 전에 모두 컴파일(정적 컴파일)을 하게 되면 컴파일 타임에 시간이 너무 오래 소요된다는 단점이 있는 대신 런타임에 성능이 뛰어나다는 장점이 있다.  반대로 javascript, python과 같이 실행 중에 컴파일을 하게 되면 컴파일 시간이 거의 필요없이 실행을 할 수 있게 되지만, 실행 중 리소스의 일부를 컴파일에 사용하게 되기 때문에 프로그램 성능이 떨어진다는 문제점이 있다.

 

이 같은 한계점을 극복하기 위해 이 둘의 단점을 최소화하고 장점을 극대화 하는 방향으로 설계된 컴파일러가 바로 JIT 컴파일러이다. JVM은 kt(kotlin)나 java 파일을 이용해 바이트 코드를 만들 때는 정적 컴파일러를 사용하지만, 바이트 코드를 기계어로 변환할 때는 동적 컴파일러를 사용하지 않는다. 동적 컴파일러를 더욱 효율적으로 동작시키기 위해 JIT(Just In Time) Compiler라 불리는 컴파일러를 지원한다.


JIT 컴파일러는 어떻게 동적 컴파일러를 최적화 하는가?


JIT컴파일러는 기본적으로 실행 중에 컴파일(동적 컴파일)을 한다. 하지만, 동적 컴파일을 하는 언어들보다 훨씬 좋은 성능을 내는데, 그 이유는 기계어로 변환된 코드를 캐시에 저장시켜 재사용시 컴파일을 다시 하지 않아도 되기 때문이다. 즉, 런타임에 바이트코드를 기계어로 변환하는 컴파일을 하면서 이미 캐시에 있는 기계어는 다시 변환하지 않고 사용하는 컴파일러가 바로 JIT 컴파일러이다. 만약 캐시된 코드를 사용한다면 마치 미리 컴파일된 코드를 사용하는 것과 같은 효과(정적 컴파일)를 내기 때문에 성능이 향상된다.

 

 하지만 JVM의 캐시 공간은 매우 작기 때문에 모든 코드들을 캐시하는건 아니다. JVM은 내부에서 자주 수행되는 코드들을 선별하여 캐시 공간에 넣어둔다. 실제로 JVM의 JIT 컴파일러 내부에는 2가지 컴파일러인 C1컴파일러와 C2컴파일러가 있다. C1 컴파일러는 런타임에 바이트 코드를 기계어로 변환하는 과정만을 수행하며 C2 컴파일러는 런타임에 바이트 코드를 기계어로 변환한다음 캐시에 저장하는 과정을 수행한다. JVM은 코드들의 수행 빈도와 복잡도에 따라 총 4가지 레벨로 분류하여 코드를 수행하는데, 이 중 1~3레벨 코드는 C1 컴파일러를 이용해 기계어로 컴파일만 수행하고 캐싱은 수행하지 않으며, 4레벨에 코드는 C2 컴파일러를 이용해 기계어로 컴파일 뿐 아니라 기계어 캐싱까지 수행한다.


바이너리 코드란?

더보기

- 바이너리 코드는 컴퓨터가 인식할 수 있는 0과 1로 구성된 이진코드를 의미한다.

CPU가 이해할 수 있는 언어


기계어란?

더보기

- 기계어는 0과 1로 이루어진 바이너리 코드이다.

- 기계어가 바이너리 코드로 구성되지만, 모든 바이너리 코드가 기계어인 것은 아니다. 

- 기계어는 특정한 언어가 아니다. 단지 CPU제조사에서 CPU를 만들 때 해당 CPU에서 사용하는 명령어 집합을 공개하는데, 이것을 '기계어'라고 부를 뿐이다. 때문에 CPU가 변경되면 기계어가 달라진다. 같은 동작을 하는 명령어지만 완전히 다른 0과 1의 나열이 될 수 있다는 말이다. 

- 아주 기본적인 연산자들은 서로 호환이 되는 편이다. 같은 회사의 CPU라도 버전별로 다른 명령을 포함할 수 있으며, 다른 회사라도 같은 명령어 집합을 공유할 수도 있다.


바이트 코드란?

더보기

- CPU가 이해할 수 있는 언어가 바이너리 코드이고, 바이트 코드는 가상 머신이 이해할 수 언어이다.

- CPU가 아닌 가상 머신에서 이해할 수 있는 코드를 위한 이진 표현법이다. 즉, 가상 머신이 이해할 수 있는0과 1로 구성된 이진코드를 의미.

- 어떤 플렛폼에도 종속되지 않고 실행될 수 있는 가상 머신용 기계어 코드이다.

- 고급언어로 작성된 소스코드를 가상 머신이 이해할 수 있는 중간 코드로 컴파일한 것을 말한다.

- 바이트 코드는 저스트 인 타임(just-in-time, JIT) 컴파일러에 의해 바이너리 코드로 변환된다.

- CPU가 텍스트를 이해하지 못하듯이 가상 머신 또한 텍스트를 이해하지 못한다.

- Java의 가상 머신을 JVM이라고 하며 JVM을 위한 바이트 코드를 자바 바이트 코드라고 한다.


출처 : https://shrtorznzl.tistory.com/82 

출처 : https://beststar-1.tistory.com/3

출처 : https://dongwoo.blog/2017/06/06/%EB%B2%88%EC%97%AD-%EC%A0%80%EC%8A%A4%ED%8A%B8-%EC%9D%B8-%ED%83%80%EC%9E%84jit-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC-%EC%A7%91%EC%A4%91-%EC%BD%94%EC%8A%A4/ 

출처 : https://connie.tistory.com/5

728x90
728x90