inline 함수
인라인 (inline) 키워드는 자바에서는 제공하지않는 코틀린 전용 키워드입니다.
코틀린을 이용하여 개발하다보면, 함수의 파라미터로 고차함수를 넘겨 사용하는 경우가 많습니다.
하지만 코틀린 공식문서에서는 고차함수를 사용하면 메모리 할당 및 가상 호출을 통해 런타임 오버헤드를 발생시켜
특정 런타임 패널티가 부과된다고 소개하고 있습니다.
인라인 함수를 이용하면, 내부적으로 함수의 내용을 함수가 호출되는 위치에 복사하여 런타임 오버헤드를 줄일 수 있습니다.
그렇다면 내부적으로 함수의 내용을 호출하는 위치에 복사한다는 것은 어떤 의미일까요?
아래와 같이 고차함수를 파라미터로 받는 함수가 있습니다.
fun executeJob(job: () -> Unit) {
println("execute new job!!")
job()
}
해당 함수를 컴파일하면 아래와 같은 자바파일이 생성됩니다.
public static final void executeJob(Function0 job) {
System.out.println("execute job!!");
job.invoke();
}
위의 선언한 함수를 이용하는 새로운 함수를 만들고, 컴파일한 자바코드는 아래와 같습니다.
fun work() {
println("start work")
executeJob { println("working..") }
println("end work")
}
public static final void work() {
System.out.println("start work");
executeJob(new Function() {
public final void invoke() {
System.out.println("working..");
}
}
System.out.println("end work");
}
자바파일에서 고차함수를 사용하기 위해 매번 새로운 객체 (new Function()) 를 만들고 있다는 사실을 알 수 있습니다.
이 의미없는 객체때문에 위에서 소개한 오버헤드 즉, 패널티가 발생하게 됩니다.
이때 inline 키워드를 함수 앞에 붙여주면, 위의 문제를 간단하게 해결할 수 있습니다.
inline fun executeJob(job: () -> Unit) {
println("execute new job!!")
job()
}
public static final void work() {
System.out.println("start work");
// inline 함수를 사용
System.out.println("execute new job!!");
System.out.println("working..");
System.out.println("end work");
}
위와 같이 inline 키워드를 이용하여 함수를 생성하면, 고차함수 매개변수에 대하여 컴파일 단계에서 새로운 객체를 생성하지 않고,
코드(자바 바이트코드) 를 복사하여 사용하게 됩니다.
reified
코틀린에서는 함수의 범용성을 늘리기 위하여 제너릭 타입을 자주 사용하곤 합니다.
fun <T> foo(classT: Class<T>): T
하지만 이러한 제너릭 타입 T 에 대한 정보는 런타임에서 Type Erase 되어버려 알 수 없게 됩니다.
따라서 일반적인 함수 body 에서 제네릭 타입에 접근하기 위해서는, Class<T> 타입을 파라미터로 전달하여 사용해야 합니다.
이러한 케이스에서 위에서 소개시켜드린 inline 키워드와 함께 reified 키워드를 사용하면,Class<T> 타입을 파라미터로 넘겨줄 필요없이, 런타임에서 타입 T 에 접근할 수 있습니다.
inline fun <reified: T> foo(): T
단, reified 키워드는 inline 함수와 조합해야만 사용할 수 있는데,
이는 inline 함수를 통해 컴파일러가 함수의 바이트코드를 함수가 사용되는 모든 곳에 복사하도록 만들기 때문입니다.
컴파일러는 reified 키워드와 함께 선언된 타입 T 를 알고 만들어진 바이트코드를 직접 클래스에 대응되도록 바꿔줍니다.
inline 함수는 만능이 아니다?
위와 같이 유용한 기능을 제공하는 inline 함수를 사용할 때, 몇가지 유의해야할 점이 있습니다.
- 기본적으로 JVM의 JIT 컴파일러에 의해서 일반 함수들은 인라인 함수를 사용했을 때 더 좋다고 생각되어지면 JVM이 자동으로 만들어주고 있다.
private접근자일 경우, 사용이 불가능하다.- 변환된 자바 바이트코드가 너무 길어질 경우, 메모리 낭비가 발생할 수 있다.
inline키워드는 1~3줄 정도 길의 함수에 사용하는 것이 효과적이다.- 특정 함수를 인라인 방식에서 제외하고 싶다면,
noninline키워드를 사용하자.
참고
https://kotlinlang.org/docs/inline-functions.html
Inline functions | Kotlin
kotlinlang.org
https://sungjk.github.io/2019/09/07/kotlin-reified.html
코틀린에서 reified는 왜 쓸까?
런타임에 Type erasure 없이 제네릭 타입을 보존시켜주는 reified 키워드에 대한 알아보았습니다.
sungjk.github.io
[Kotlin] Inline-Funtions 과 Reified 사용 이유
실무를 하다가 inline이 사용된 메소드를 발견하게 되어 뭐하는 명령어인가.. 궁금해져 정리한 포스트입니다.
velog.io