with ChatGPT 시리즈는 ChatGPT의 내용과 개인의 생각을 토대로 학습해 보는 컨텐츠입니다.
Kotlin은 고차 함수와 람다를 매우 자연스럽게 지원하는 언어입니다.
하지만 람다의 사용은 런타임 성능에 영향을 줄 수 있는 추가 비용을 발생시키기도 합니다.
이 문제를 해결하기 위해 Kotlin은 inline, noinline, crossinline이라는 키워드를 제공하여 함수 호출, 람다 전달, 제어 흐름 최적화를 조절할 수 있도록 합니다.
이번 글에서는 이 키워드들의 개념과 차이, 그리고 실무에서의 활용 시점을 함께 알아보겠습니다.
🔹 1. inline 함수란?
inline 키워드는 함수 호출 자체를 컴파일 타임에 해당 코드로 대체 (inline) 하도록 요청하는 기능입니다.
inline fun log(block: () -> Unit) {
println("Start")
block()
println("End")
}
log {
println("Hello")
}
👉 위 코드는 컴파일 시 다음처럼 변환됩니다.
println("Start")
println("Hello")
println("End")
✅ inline을 사용하는 이유
- 함수 호출 오버헤드 제거 → 성능 향상
- 람다 생성과 캡처 비용 줄이기
- non-local return 허용 (→ 아래 설명)
특히 자주 호출되는 간단한 고차 함수 (예: lock, measureTimeMillis, runBlocking)에서 유용
🔹 2. non-local return이란?
inline 함수 안에 전달된 람다에서는 호출된 함수의 바깥으로 return 할 수 있습니다.
inline fun run(block: () -> Unit) {
block()
println("run() end")
}
fun test() {
run {
println("inside block")
return // ✅ test() 함수 자체에서 return됨
}
println("unreachable") // 컴파일 오류
}
이런 동작은 inline 함수이기 때문에 가능하며, 컴파일러가 코드를 복사해서 붙여 넣기 하기 때문에 제어 흐름이 바깥 함수까지 영향을 미칩니다.
🔹 3. noinline: 인라인 하지 말 것
inline 함수 내에 전달된 람다 중 일부만 인라인 하고 싶지 않을 때 noinline을 사용합니다.
inline fun analyze(
inlineBlock: () -> Unit,
noinline afterBlock: () -> Unit
) {
inlineBlock() // 컴파일 타임 인라인
afterBlock() // 런타임 람다 호출
}
예를 들어 람다를 변수로 저장하거나, 다른 함수에 전달해야 하는 경우엔 인라인 할 수 없기 때문에 noinline이 필요합니다.
🔹 4. crossinline: non-local return 금지
람다를 인라인 하되, non-local return을 금지하고 싶을 때 crossinline을 사용합니다.
inline fun launch(crossinline block: () -> Unit) {
val r = Runnable {
block() // ✅ 가능
// return ❌ 컴파일 에러 (non-local return 금지됨)
}
Thread(r).start()
}
람다를 객체나 다른 컨텍스트에서 호출할 경우, non-local return은 위험하므로 금지되어야 합니다.
이런 상황에서 crossinline이 필요합니다.
🔍 정리 예제
inline fun wrap(
inlineBlock: () -> Unit,
noinline fallback: () -> Unit,
crossinline action: () -> Unit
) {
inlineBlock() // 인라인 가능
fallback() // 객체 전달 가능
Thread { action() }.start() // return 사용 불가
}
🧪 성능 측면에서의 영향
항목 | 설명 |
inline 사용 | 호출 오버헤드 제거, 객체 생성 최소화 |
noinline 사용 | 일반적인 람다처럼 동작, 함수 인자로 전달 가능 |
crossinline 사용 | 인라인하면서도 return 제어 |
주의할 점 | 너무 많은 인라인은 코드 크기 증가 (→메소드 인플레이션) |
예: repeat(100_000) 같은 반복에서 고차 함수를 인라인 하면 성능 개선 효과가 큼
✅ 실무에서 어떻게 활용할까?
상황 | 키워드 선택 |
단순 람다 블록 + 성능 중요 | inline |
람다를 저장하거나 전달 | noinline |
람다를 다른 스레드나 객체에서 실행 | crossinline |
DSL 구성이나 builder 패턴 | inline + crossinline 조합이 일반적 |
🚀 결론
키워드 | 의미 | 특징 |
inline | 호출 코드를 인라인 | 람다 비용 최소화, non-local return 가능 |
noinline | 인라인 제외 | 람다 저장, 전달 가능 |
crossinline | 인라인하되 return 금지 | 다른 컨텍스트에서 람다 실행할 때 사용 |
Kotlin의 inline, noinline, crossinline은 함수형 스타일과 성능 최적화 사이에서 유연하게 조절할 수 있는 중요한 도구입니다.
단순 문법 같지만, 성능과 코드의 안정성에 깊은 영향을 줄 수 있는 고급 기능입니다.
🤔 추가로 생각해 볼 질문들
- Kotlin 컴파일러가 언제 자동으로 inline 최적화를 적용할까?
- inline 함수는 어떻게 디버깅하는 것이 좋을까?
- crossinline 없이 non-local return을 허용하면 어떤 문제가 생길까?
- 인라인 함수가 코드 크기에 어떤 영향을 주는가?
- inline class와 inline function은 어떻게 다를까?