1. 개요
바이트코드(Bytecode)는 고급 언어로 작성된 소스 코드를 가상머신이 이해할 수 있는 중간 코드로 컴파일한 것을 말한다. 쉽게 말하자면 가상머신을 위한 기계어로, 가상머신이 있는 곳이라면 대체로 함께 존재한다고 보면 된다. 이 때문에 가상머신용 오브젝트 코드까지 바이트코드라 부르는 일도 있다. '기계어'이니만큼 당연히 이에 대응되는 '어셈블리어'도 존재한다.원시 코드에서 바이트코드로는 컴파일로 진행되고, 가상머신은 이 바이트코드를 실제 머신에 맞게 구현된 인터프리터로 해석해 대응되는 실제 머신 기계어 코드를 실행한다. 바이트코드 생성까지는 컴파일이고, 바이트코드 자체는 인터프리터 언어라는 것이다. 덕분에 (텍스트를 직접 읽어 실행하는) 인터프리터 언어의 단점인 느린 실행 속도를 극복하면서도 동시에 (가상머신이라는 단일 종류의 구현을 통해) 호환성이 보장된다. 실행 속도는 순수 컴파일러 언어와 순수 인터프리터 언어의 중간 수준이다.
바이트코드라는 명칭은 Java 및 JVM에서 대표적으로 사용하는데, 다른 가상머신용 바이트코드까지 통틀어 바이트코드라고 부르는 경우도 있어 혼동 방지를 위해 'Java 바이트코드'라고 명시적으로 기술하는 경우가 많다. 또한 굳이 '바이트' 형식의 코드를 지칭할 필요가 없는 경우도 있어, 가상머신 환경마다 부르는 명칭이 달라지기도 한다. 아예 '바이트코드'를 부르는 명칭 없이 상위 개념인 중간 언어로 어셈블리어 형식과 바이트코드 형식을 통틀어 언급하는 경우도 많다.
실행 속도 문제를 완화할 수 있다는 장점 때문에, Python 등 일부 인터프리터 언어에서는 구현체에서 바이트코드를 생성하기도 한다. 주로 (생성 또는 수정 후) 첫 실행 시 바이트코드를 생성해 캐싱해 두고, 원시 코드가 바뀌지 않는 한 생성해 두었던 바이트코드를 재활용하는 형태로 이용된다. Python을 다루다보면 *.py 파일 말고도 *.pyc로 된 파일을 볼 수 있는데, 이 *.pyc 파일이 바로 Python 바이트코드이다.
전술했듯 순수 인터프리터 언어에 비해 실행 속도가 충분히 빠르긴 하지만 순수 컴파일러 언어에 비해선 여전히 느리다. 때문에 원시 코드를 바이트코드로 번역하는 과정에 이어 바이트코드를 실제 기계어로 번역하는 컴파일러도 생겨났는데, 이게 바로 AOT(Ahead-of-time) 컴파일러이다. 가상머신을 거치지 않고 바로 실제 머신에서 실행할 수 있기에 실행 속도는 순수 컴파일러 언어 수준으로 빨라지지만, 대신 가상머신으로 보장되던 호환성은 일부 깨지게 된다. 물론 컴파일러의 지원 범위 내에서라면 같은 코드를 그대로 돌려쓰면 되기에 호환성이 완전히 깨지는 것은 아니다.
2. 종류
- .NET CLR에서는 CIL(Common Intermediate Language)이라는 이름의 바이트코드가 사용된다.
- 액션스크립트 바이트코드
- Java 바이트코드
- Dalvik 바이트코드: 안드로이드 런타임에서 구동되는 Java 바이트코드로, 이 바이트코드로 이뤄진 dex 파일을 분해하여 가독성을 높인 코드가 smali다. 이를 활용하여 APK 파일을 변경할 수 있다.
- WebAssembly