질문을 해결하는 과정

[Java] 인사팀 과장님도 무릎을 탁 치는 자바를 컴파일 하는 과정 정리

무자비한 낭만주먹 2024. 1. 3. 00:16

[그림1]. 오늘도 감사한 공부 시작 ~

목차
0. 개요
1. 컴파일에 대해서
2. 컴파일이 일어나는 대략적인 맥락
3. Java Virtual Machine을 위한 언어
4. 자바에서 컴파일이 일어나는 대략적인 맥락
5. 결론

 

 

0. 개요
a. 쌔한 느낌
Q. 자바를 컴파일 하는 과정이 어떻게 돼요?


- 최근에 들었던 질문인데, 대답하다 보니 "내가 잘 이해도 못하고 외우기에만 급급했구나" 라는 생각이 들었다. 그래서 이번 기회에 정리해보기로 했는데 어차피 복잡하게 정리하면 중간에 또 까먹을거라 최대한 이해하기 쉽게 정리해보기로 했다.

b. 염두할 것
'자바 컴파일' 과정을 쉽게 표현하는게 목적임을 잊지 말자


- 생각을 하다보니 또 GC니 JVM 구조니 복잡해져서 최대한 자바 컴파일을 쉽게 설명하도록 글을 쓰기로 했다.

 

2023년 마지막 날이라 뭔가 느낌이 묘하지만, 어쨌든 시작해보자.

 

1. 컴파일에 대해서
a. 컴파일이란?
Q. 아니 근데 컴파일이 도대체 뭐야?
[그림2]. 컴파일이란 번역이다


- 컴파일은 '번역'하는 것 이다.
- 컴퓨터에게 명령을 내리는 '프로그래머의 언어'와 시키는 대로 일하는 '컴퓨터의 언어'가 다르기 때문에 우리는 번역이 필요하다.

b. 컴파일러의 역할
Q. 아 그러니까 컴퓨터한테 일시키기 위해서 '사람 말'을 기계가 이해하는 말로 번역하는 거라는거지?

 

[그림3]. 컴파일러의 역할


- 우리는 영어, 중국어, 한국어 같은 자연 언어를 사용하지만 컴퓨터는 0과 1로 이루어진 이진 언어를 사용한다.
- 물론 대부분의 프로그래밍 언어는 영어이지만 어쨌든 사람의 언어를 컴퓨터의 언어로 번역하는 걸 컴파일이라고 한다.

 

결론은 컴파일러는 "사람의 말을 기계의 말로 번역하는 놈이다"

 

2. 컴파일이 일어나는 대략적인 맥락
a. 추상적인 컴파일 과정
Q. 컴파일 흐름을 대충 표현하면 어떻게 되는거야?
[그림4]. 대략적인 컴파일의 흐름


- 우리가 자연어 (영어 등..)로 코드를 작성하면 컴파일을 통해 컴퓨터가 이해할 수 있는 이진 언어로 번역한다.
- 컴퓨터는 번역된 명령이 작업 목록에 올라오면 이 내용을 보고 작업을 수행한다.

* 여기서 번역된 명령을 수행하는 놈은 CPU, 작업 목록은 메모리, 명령 내용은 프로그램으로 굳이 어렵게 표현하면 "메모리에 프로그램이 올라오면 하나의 프로세스로서 운영체제의 관리를 받게되며 CPU가 해당 작업을 수행한다."라고 표현할 수 있다. (잘 모르겠다 싶으면 그냥 지금은 이해 안해도 됌)

b. 컴파일의 결과는 무조건 이진 코드인가
Q. 아하 그럼 컴파일 결과는 무조건 이진 코드겠네요? 그게 컴퓨터가 이해하는 언어니까?

 

[그림5]. 그건 또 아닌데 ..


- 앞선 설명에선 쉬운 이해를 위해 조금 더 직접적인 이진 코드의 예시를 들었지만 사실 여러 예외가 존재한다.
- 그 중 오늘 주된 예시로 다루려는 자바의 경우 'Java Virtual Machine'(JVM)이라는 '프로그램으로 구현한 가상의 기계'가 중간에 끼어 있어서 컴파일 결과로 '자바 바이트 코드'라는 것도 추가로 나오게 된다.

* 사실 C++ 이나 다른 언어들의 경우도 설명하면 오늘 다루는 문제에 대한 복잡도가 많이 증가해서 일단 자바에 한정해 설명한다.

 

결론은 컴파일러가 만들어내는 번역은 오롯이 "실제 컴퓨터를 위한 이진 코드" 뿐 아니라 어떤 방식의 컴파일이냐에 따라 여러 결과물이 나올 수 있으며 자바의 경우 Java Virtual Machine이라는 가상의 기계를 위한 언어로 '번역' 해준다.

 

3. Java Virtual Machine을 위한 언어
a. 중간에 기계가 하나 더 추가된 것
Q. 그니까 자바 버츄얼 머신인지 문신인지가 추가돼서 걔를 위한 언어로 번역해야 한다는거죠?
[그림6]. 하나 더 추가된 '번역' 대상


- 기존에는 바로 기계에게 번역본을 전달했다면 이제는 JVM이라는 녀석을 위한 번역본을 만든다.
- 굳이 JVM 이라는 녀석을 두는 이유는 "한 번 컴파일(번역)한 번역본을 가지고 모든 기계에게 명령하기 위해서"다.
- 사람의 언어도 '미국어', '중국어' 등 .. 다양하듯이 기계의 언어도 이진 코드이지만 다른 경우가 있다. 그래서 개발자가 바로 기계가 이해하는 언어로 컴파일을 해버리면 다른 기계 언어를 사용하는 기계에게 명령할 때 그 기계에 맞춰 컴파일(번역)을 다시 해야하는 일이 생긴다.
- 그래서 JVM이라는 녀석이 이해할 수 있는 언어로 컴파일을 하는데, JVM이라는 건 각 기계의 언어에 맞는 번역을 할 수 있는 놈들이 다 있어서 기계를 바꾸지 않아도 해당 기계에 맞는 JVM를 설치해 바로 실행할 수 있게된다.
- 사실 이런 문제를 기계를 바꾸는 걸로 해결하지 않는 이유는 기계는 실제 물리적으로 존재하는 녀석이어서 바꾸기 힘들지만, JVM은 프로그램이기 때문에 그냥 새로 깔면되서 교체가 쉽기 때문이다.

* 이 내용이 조금 복잡하다면 "자바는 실제 기계가 아니라 JVM이라는 가상 기계를 위한 언어로 코드를 먼저 번역 하는구나"정도만 이해하고 넘어가도 된다.

결론은 자바는 "실제 기계가 아니라 JVM이라는 가상 기계를 위한 언어로 코드를 먼저 컴파일(번역)한다"

 

4. 자바에서 컴파일이 일어나는 대략적인 맥락
a. 추상적인 자바의 컴파일 과정
Q. 그럼 자바 컴파일 흐름을 대충 표현하면 어떻게 되는거야?
[그림7]. 자바의 추상적인 컴파일 과정


- 자바에서 컴파일은 2군데서 일어난다. 
- 첫 번째 컴파일은 자바의 코드를 JVM이 이해할 수 있는 자바 바이트 코드로 번역하기 위해서이며
- 두 번째 컴파일은 JVM이 자바 바이트 코드를 동적으로 실행하는 와중에 성능상의 요건을 위해 많이 쓰이는 부분을 실제 컴퓨터(CPU)가 이해할 수 있는 이진 코드로 번역할 때 이다.

결론은 자바의 경우 컴파일은 총 두 번 일어나며 첫 번째는 자연 코드를 자바 바이트 코드로 번역할 때 이며 두 번째는 자주 쓰이는 자바 바이트코드를 기계어(이진 코드)로 번역할 때 이다.

 

5. 결론
오늘 기록의 결론은 "컴파일은 번역이며 우리의 언어로 작성된 코드를 기계가 이해할 수 있는 언어로 번역하는 것이다. 우리는 이렇게 기계가 이해할 수 있는 언어로 번역된 코드를 '프로그램'이라고 부르는데 프로그래머 관점에서의 컴파일이란 '자연어로 작성된 코드를 프로그램으로 만드는 것'이다.  자바로 작성된 코드로 프로그램을 만들기 위해선 2번의 번역 작업이 필요하며 이는 각각 "자연 언어로 작성된 코드를 JVM이 이해할 수 있는 자바 바이트 코드로 번역"하는 작업과 "많이 사용되는 자바 바이트 코드를 기계가 이해할 수 있는 기계어(이진 코드)"로 번역하는 과정이다.

 

 

오늘 하루도 공부할 수 있어 크게 감사합니다.

2024-01-01 개발자 최찬혁