TIL 96 - Compiler, Interpreter, JIT

김영현·2024년 5월 30일
0

TIL

목록 보기
107/129

컴파일러

컴퓨터(CPU)에게 명령을 내리려면, 0과1로 이루어진 언어(기계어)를 전달해 주어야한다.
따라서 사람이 이해하기 쉬운 언어로 작성된 코드를 기계어로 변환하는 과정이 필요하다.

고급언어(C언어같은...) => 어셈블리어 => 기계어

그 과정 자체를 컴파일이라 말하며 일련의 과정을 행해주는 소프트웨어를 컴파일러라고 한다.

어셈블리어

기계어만 존재하던 시절, 기계어로 코딩하는게 너무 어려운 나머지 기계어를 한 단계 추상화 한 언어가 등장했다.
그게 바로 Assembly Language.

예를들어 1011 1011이라는 기계어 명령어를 어셈블리어인 mov 대체한다.
사람이 읽고 쓰기 쉬운 코드가 된 것이다.

그런데 의문은, 아직도 컴파일 할때 어셈블리어를 사용한다는 것이다. 고급 언어에서 바로 기계어로 번역할 순 없을까?

해답은 의외로 간단하다.

고급 언어를 바로 기계어로 번역하지 않는 이유

기계어로 바로 번역하는 건 어려운 작업이며 설사 번역을 거쳤다 한들, 최적화, 디버깅등에 문제가 있기 때문이다.

0과 1로 이루어진 기계어 vs 고급언어는 아니지만 사용자가 인식하기 쉬운 언어
디버깅, 기타 최적화 관점에서 본다면 당연히 그나마 사용자가 인식하기 쉬운 어셈블리어가 유리하다.

따라서 바로 기계어로 번역하지 않는 것이다.

물론 예외가 존재한다!
이를 Single pass compile이라 부르며 중간단계어셈블리어를 거치지 않고 바로 기계어로 번역하는 컴파일러가 있다.


인터프리터

컴파일소스코드를 기계어로 번역하는 과정 이었다. 이에 비해 인터프리터는 소스코드를 한 번에 컴파일 하지 않고 한 줄씩 컴파일한다. 비교대상이 다르지만 Node.js의 입출력 모듈 중 readFilereadline의 차이하고 비슷하다 볼 수 있다.
한 번에컴파일 하느냐 한 줄마다컴파일하느냐의 차이다

하지만 한 줄씩 컴파일하면 컴파일러와 속도 차이가 꽤 많이 날것 이다. 이를 해결하기위하여 소스코드를 가상머신타겟의 바이트코드로 변환하거나 자주쓰이는(반복적) 함수, 클래스등의 기계어를 캐싱하는 JIT컴파일러를 인터프리터에 내장하는 방식이 도입되었다.

가상머신은 뭐고 바이트코드는 뭐지...?!

가상머신, 바이트코드

가상머신을 직역하면 물리적으로 존재하는 컴퓨터가 아닌 가상의 컴퓨터를 뜻한다.

예를들어 C 언어를 생각해보자. C 언어컴파일과정을 거쳐서 프로그램을 바로 실행할 수 있다.
이에비해 Javascript컴파일이 아닌 인터프리터를 거쳐 프로그램을 바로 실행할 수는 없다.
이때 JS를 실행하기위한 환경들 Node.js, 브라우저...가상머신이라 칭하는 것이다.

아하 그러니까 결국 언어실행하는 환경가상머신이라 칭하게 되는거구나.
그렇다면 바이트코드는 무슨의미일까?

바이트 코드가상 머신이 이해할수 있는 중간 표현으로 컴파일 한 것을 말한다.
기계어고급 언어사이에 있는 어셈블리어에 가까운 형태를 띄고있다.

바로 윗 목차에서 나온 내용은 결국 인터프리터의 속도가 느리니 컴파일과정을 거쳐 속도를 올렸단 거구나.

참고로 바이트코드는 인터프리터 방식으로 해석한다. 즉 바이트코드를 생성하는것 까지가 컴파일! 바이트코드 자체는 인터프리터의 언어다.

번외) IR(intermediate representatio, 중간언어, 중간표현)

중간 표현이란 컴파일러,가상머신에 의해 내부적으로 사용되는 데이터구조 or 코드이다.

언어가 아니라 표현이라고 되어있다. 또한 데이터 구조도 포함된다. 즉, 언어에 국한되지 않아 스택, 튜플등도 이에 해당된다는 의미이다.

인터프리터에서만 쓰일 것 같지만, 컴파일러에서도 많이 쓰인다. 보통 2개의 IR을 사용하는데, low level language버전과 high level language버전을 사용한단다.

인터프리터와 기계어 헷갈렸던 부분(해결)

어디서는 인터프리터기계어로 번역하지 않는다 하고 어디서는 기계어로 번역한다고 되어있었다.
결국 알아낸 사실은...

  1. 태초의 인터프리터는 한 줄씩 기계어로 번역하였다. 그러나 속도면에서 컴파일러와 차이가 심했다.
  2. 인터프리터를 최적화 하기위해 소스코드를 기계어로 바로 바꾸는 대신 가상머신이 이해할 수 있는 바이트코드로 변환하였다.
  3. 가상 머신이 프로그램을 대신 기계어로 컴파일 후 실행해준다.
  4. 짜잔 기계어로 번역하지 않는 인터프리터 완성!

1번에서 언급된 기존의 인터프리터를 pure interpreter라고 하며 요즘 사용되는 인터프리터를 Bytecode Interpreter라고 칭한다.


JIT(Just-In-Time) Compile

JIT는 즉시라는 뜻이다. 즉, 즉시 컴파일 한다는 뜻이다. 마치 기존의 인터프리터인 pure interpreter같지 않은가?

  • 처음 실행될때 인터프리트를 하여 자주 쓰이는 코드를 캐싱한다.
  • 인터프리트 과정이 들어가기에 당연히 기존의 컴파일방식하고 비교하면 느리다.
  • 하지만 인터프리터자체를 사용하는 것 보단 빠르다.

요약하자면 인터프리터컴파일방식을 혼합한 방식이다. 아마 제일 최신 방식 아닐까?
자세한 방식은 다음편(JS를 CPU에게 전달하기까지...)에서 같이 알아보겠십니더😲

profile
모르는 것을 모른다고 하기

0개의 댓글