[CS] 컴파일 언어 VS 인터프리터 언어, 그리고 Java
컴파일 언어와 인터프리터에 관한 내용입니다.
컴파일 언어 VS 인터프리터 언어
- 항상 접할때마다 헷갈려서 정리하기로 했다.
컴파일 언어
- 한번에 전체 코드 번역
- 소스코드를 기계어로 변환하는 과정(컴파일)을 거친 후 실행
- 실행 파일이 생성됨으로 배포에 용이함
- 컴파일 타임 사용
- 이 과정을 거쳐 소스코드는 기계어가 되어 실행가능한 상태가 됨
- 실행 속도
- 기계어로 변환된 상태에서 실행되므로 매우 빠름
- 인터프리터 언어보다 20~100배 이상 빠름
- 개발 과정
- 문법 오류를 실행 전에 발견할 수 있어 안정적임
- 하지만 코드 변경 시 다시 컴파일해야 하므로 개발 편의성이 다소 떨어짐
- 대표적인 언어
- C, C++, 러스트, Go 등
인터프리터 언어
- 스크립트 언어
- 별도의 실행 파일 없이, 소스코드를 직접 실행하는 경우가 많음
- 번역과 실행이 동시에 이루어짐
- 프로그램을 실행할 때 한 줄씩 읽고 해석한 뒤 바로 실행
- 런타임 사용
- 실행 시점에 코드가 해석되므로 빌드 과정이 필요 없음
- 실행 속도
- 한 줄씩 해석하며 실행하므로 컴파일언어보다 느림.
- 개발 과정
- 즉시 실행 및 테스트가 가능하여 개발 속도가 빠름
- 동적 타입을 지원하는 경우가 많아 코드 수정이 용이
- 대표적인 언어
- Python, Ruby, JavaScript 등
- 기타 특징
- python은 C++로 만들어져 있음
- 컴파일 언어는 빠르지만 개발 편의성이 떨어져 인터프리터 언어를 만드는데 사용되기도 함
- 실행 속도를 개선하기 위해 JIT(Just-In-Time) 컴파일러를 사용하는 경우도 있음
- Python의 PyPy, Javascript의 V8엔진 등
- python은 C++로 만들어져 있음
왜 인터프리터 언어가 더 느릴까?
- 인터프리터 언어가 빌드 과정이 없는데 왜 느릴까?
- ‼️ 코드를 실행하는 방식 때문!
1. 한 줄씩 해석하며 실행하기 때문
- 컴파일 언어는 미리 전체 코드를 기계어로 변환한 후 실행하지만, 인터프리터 언어는 실행할 때마다 한 줄씩 해석하고 실행
- 컴파일 언어
- 실행 전에 한 번만 컴파일 -> 실행 시에는 기계어(0과1)로 바로 실행 -> 속도가 빠름
- 인터프리터 언어
- 실행할 때마다 소스 코드를 읽고, 해석하고, 실행 -> 한 줄씩 번역하면서 실행해야 해서 속도가 느림
2. 동적 타입 (dynamic typing) 지원이 많아서
- 대부분의 인터프리터 언어 (Python, JavaScript 등)는 동적 타입 (dynamic typing)을 지원
- 동적 타입 언어는 실행 중 변수의 타입을 결정하기 때문에 매 실행마다 타입 체크가 필요
- 반면, 컴파일 언어(C, C++ 등)는 컴파일 시점에 타입이 결점되므로 실행 속도가 훨씬 빠름
3. 최적화 부족
- 컴파일러는 최적화(Optimization)를 통해 코드를 더 효율적으로 변환함
- 예를 들어, 컴파일러는 불필요한 연산을 제거하고, 반복문을 최적화하는 등 실행 속도를 높이기 위해 다양한 작업 수행
- 인터프리터 언어는 실행할 때마다 소스 코드를 직접 해석하기 때문에 이런 최적화가 어려움
4. 메모리 관리 방식 차이
- 컴파일 언어는 메모리 할당을 미리 최적화할 수 있지만, 인터프리터 언어는 실행 중에 동적으로 메모리를 할당하는 경우가 많아 메모리 관리 부담이 큼
그럼 인터프리터 언어의 속도를 높이는 방법은?
✅ 1. JIT(Just-In-Time) 컴파일
- JIT 컴파일러는 인터프리터 방식과 컴파일 방식의 장점을 결합한 방법
- 프로그램 실행 도중 자주 실행되는 코드 블록을 미리 기계어로 변환해서 속도를 높임
- 대표적 예시
- Java의 JVM (HotSpot JIT 컴파일러)
- Python의 PyPy
- JavaScriptdml V8 엔진 (Chrome, Node.js)
✅ 2. 바이트코드(Bytecode) 사용
- 일부 인터프리터 언어는 소스 코드를 직접 해석하는 대신, 한 번 중간 코드(바이트코드)로 변환한 후 실행하는 방식을 사용
- 예: Python의 CPython(기본 구현체)
- Python 소스 코드(.py) -> 바이트코드(.pyc) 변환 -> 실행
- 덕분에 매번 소스 코드를 해석하는 부담이 줄어듦
🔹 Java는 어떻게 실행될까?
- Java는 전통적인 컴파일 언어와 인터프리터 언어의 특징을 혼합한 하이브리드 언어
1️⃣ 소스 코드 → 바이트코드 변환 (컴파일 과정)
- Java 코드를 작성하면, javac 컴파일러가 이를 바이트코드(Bytecode) 로 변환.
- 바이트코드는 완전한 기계어가 아니라 JVM(Java Virtual Machine)에서 실행할 수 있는 중간 코드
- 이 과정은 전통적인 컴파일 언어(C, C++)와 비슷하지만, 완전히 기계어로 변환되지 않고 플랫폼 독립적인 코드로 남아 있음.
2️⃣ JVM에서 바이트코드 실행 (인터프리터 + JIT 컴파일)
- Java의 실행 과정에서는 JVM(Java Virtual Machine) 이 핵심 역할을 수행
- JVM은 바이트코드를 한 줄씩 읽고 실행하는 인터프리터 방식을 사용하지만, 성능을 높이기 위해 JIT(Just-In-Time) 컴파일러를 활용.
🔹 JIT(Just-In-Time) 컴파일러가 하는 일
JIT 컴파일러는 인터프리터와 컴파일 방식의 장점을 결합한 기술이야.
- 실행 중 자주 사용되는 바이트코드를 분석해서 기계어로 변환(컴파일)한 후 캐싱해 둠.
- 이후 같은 코드가 실행될 때는 다시 해석하지 않고, 컴파일된 기계어를 바로 실행해서 성능을 높여.
- 즉, Java는 처음에는 인터프리터처럼 실행되지만, JIT이 동작하면 컴파일된 기계어 코드가 사용되므로 속도가 빨라지는 것이야.
🔹 Java는 컴파일 언어일까? 인터프리터 언어일까?
✔ 둘 다 아님! Java는 하이브리드 방식을 사용
- 컴파일 언어처럼: 소스 코드를 바이트코드로 변환하는 컴파일 과정이 있음.
- 인터프리터 언어처럼: JVM이 바이트코드를 한 줄씩 해석하며 실행할 수도 있음.
- JIT을 사용하면: 실행 중 특정 코드 블록을 기계어로 컴파일해서 성능을 높임.