공부가 필요한 문법에 대해서 정리한 글입니다.
필자는 문뜩 코드를 작성하고 있지만
어떻게 코드가 동작하고 있는가에 대해 생각할 필요가 있다고 생각했습니다.
그래서 오늘은 잘 사용하고 있는Kotlin의 동작과정을 파해쳐 보려고 합니다.
Compiler는 특정 프로그래밍 언어로 쓰여 있는 문서를
다른 프로그래밍 언어로 옮기는 언어 번역 프로그램입니다.
즉 현재 많은 프로그램은 컴파일러를 통하여 전체를 기계어로 번역하여 실행합니다.
또한 소스를 한꺼번에 번역하지 않고 명령 하나하나를 실행시키는 해석기는인터프리터로 분류합니다.etc : 한 언어의 컴파일러를 자신의 언어로 재작성하는 것을 부트스트래핑이라고 한다.
코틀린은 JVM(Java Virtual Machine) 위에서 동작하며
정적 타입의 프로그래밍 언어입니다.
- 정적 타입 언어 : 컴파일 시간에 변수의 타입이 결졍되는 언어 (ex : c, c++, java, kotlin)
- 동적 타입 언어 : 런타임 시간에 변수의 타입이 결졍되는 언어 (ex: JavaScript, Python)

Kotlin의 컴파일 과정은 JVM 위에서 동작하기 때문에 Java 컴파일 과정과 유사합니다.
.kt 파일은 Kotlin Compiler를 통해 바이트 코드로 변환되고
Kotlin Runtime Kibrary에 의존되어 실행됩니다.Kotlin Runtime Library에는 Kotlin 표준 라이브러리, Java API를 확장한 내용 등이 존재
쉽게 말하면 소스 코드 작성 -> 컴파일러를 통해 바이트 코드 변경 및 메모리 적재 -> JVM 실행
순서대로 동작하지만 자세하게 쪼개봅시다.
단순하게
Hello World를 출력하는 소스 코드를 작성한다고 생각해봅시다.
fun main() {
println("Hello Kotlin")
}
코틀린 컴파일러는
kotlinc명령어나 IDE(통합 개발 환경)에서 자동으로 실행됩니다.
1. 전처리
- 코드를 문자 단위로 잘라서 토큰(Token)으로 변환합니다.
fun,main,println같은 키워드들을 구분합니다.- 파서(Parser)가 토큰의 문법 구조를 해석합니다.
- 어떤 것이 함수인지, 변수인지 문법적으로 분석합니다.
- AST(Abstract Syntax Tree)을 생성합니다.
- 코드를 트리 형태로 변환합니다.
2. 중간 표현(IR)
- AST를 바탕으로 중간 표현(IR)으로 변환합니다.
- 코틀린은 독자적인 Kotlin IR을 사용합니다.
- 이 단계에서는 최적화 작업이 수행됩니다.
- Dead Code 제거
- 인라인 함수 최적화
- 람다 표현식 변환
- Null 체크 최적화 등
3. 바이트코드 생성
최종적으로 중간 표현을 JVM이 이해할 수 있는 바이트코드(Bytecode)로 변환합니다.
// ================basic/HelloWorldKt.class =================
// class version 52.0 (52)
// access flags 0x31
public final class basic/HelloWorldKt {
// compiled from: helloWorld.kt
@Lkotlin/Metadata;(mv={1, 9, 0}, k=2, xi=48, d1={"\u0000\u0008\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001\u00a8\u0006\u0002"}, d2={"main", "", "kotlin_lauguage_study"})
// access flags 0x19
public final static main()V
L0
LINENUMBER 4 L0
LDC "Hello World!"
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
SWAP
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L1
LINENUMBER 5 L1
RETURN
MAXSTACK = 2
MAXLOCALS = 0
// access flags 0x1009
public static synthetic main([Ljava/lang/String;)V
L0
INVOKESTATIC basic/HelloWorldKt.main ()V
RETURN
L1
LOCALVARIABLE args [Ljava/lang/String; L0 L1 0
MAXSTACK = 0
MAXLOCALS = 1
}
그럼 여기서 의문이 들 수 있는데? 왜 바이트코드로 변환될까요?
그것에 대한 답은 JVM은 바이트코드(중간 코드)만 이해할 수 있기 때문입니다.
컴파일이 완료되면
.class파일이 생성됩니다.
//명령어로 확인하는 방법
kotlinc Main.kt
JVM(Java Virtual Machine)은.class파일에 있는 바이트 코드를 실행합니다.
- ClassLoader
- ClassLoader가 .class 파일을 메모리에 로드합니다.
- 코틀린에서는 KotlinClassLoader라는 자체 클래스 로더가 사용됩니다.
- Bytecode Verification
- 바이트코드가 유효한지 검증합니다.
- 메모리 접근 오류
- 형변환 오류
- 스택 오버플로우 등
- Just-In-Time (JIT) 컴파일
- JVM은 처음에 바이트코드를 해석기로 실행합니다.
- 자주 실행되는 코드는 JIT 컴파일러가 실시간으로 기계어 코드로 변환합니다.
- 실행(Execution)
- 기계어로 변환된 코드를 CPU가 실행합니다.

코틀린은 자바보다 더 효율적인 최적화 작업을 수행합니다.
- Null Safety (NPE 방지)
- Inline 함수 (코드 크기 최적화)
- Tail Recursion (스택 오버플로우 방지)
- Smart Casting (타입 캐스팅 최소화)
또한 JVM 안에서 자동적으로
Garbage Collection을 통해서
불필요한 메모리르 알아서 정리해줍니다.
- Mark And Sweep
- G1 Garbage Collector
코틀린은 왜 JVM을 사용할까? 라는 생각이 들 수 있는데
코틀린은 처음부터 자바와 호환되는 대체 언어로 설계되었으며
자바 프로젝트와 함께 사용할 수 있도록 설계되었습니다.
개발자가 자바에서 코틀린으로 쉽게 전환 가능한 언어이기에
코틀린의 목표이념을 잘 알고 기존 자바 라이브러리와 호환하여 사용해봅시다!