[Kotlin] Inline 키워드를 사용하는 이유

오규성·2025년 11월 7일

Kotlin

목록 보기
3/3
post-thumbnail

Inline Keyword

Lambda 를 사용하는 function 에서 사용하는 키워드로 컴파일 시 함수의 코드를 호출부에 복사하고, 해당 함수를 직접 호출하지 않아 성능상 이점을 제공해준다.

코드를 작성할 때, Lambda 를 사용해봤을 것이다.
Lambda 를 사용하면 호출부에서 설정해준 코드를 필요할 때마다 꺼내 쓸 수 있으므로 매우 편리하다.

하지만 이러한 Lambda 에는 한 가지 단점이 있다.

일반적으로 function 에서 Lambda 를 실행하는 경우 Compile 과정에서 새로운 Lambda Function 를 생성하고, 이를 실행한다.

// 이 코드는 컴파일 시
fun A(){ 
    B{
        println("B 람다입니다.")
    }
}
fun B(
    lambda: () -> Unit
){
    lambda()
    println("B입니다.")
}

-----------------------------
public final class DevGyuTestScreenKt {
   public static final void A() {
      B(DevGyuTestScreenKt::A$lambda$0);
   }

   public static final void B(@NotNull Function0 lambda) {
      Intrinsics.checkNotNullParameter(lambda, "lambda");
      lambda.invoke();
      System.out.println("B입니다.");
   }

   private static final Unit A$lambda$0() {
      System.out.println("B 람다입니다.");
      return Unit.INSTANCE;
   }
}

즉, 불필요한 객체 생성과 함수 호출이 발생할 수 있다.
그런데 Inline function 을 사용하면, Lambda 내부 코드를 기존의 호출부에 그대로 가져다 쓰기 때문에 이를 방지할 수 있다.

fun A(){
    B{
        println("B 람다입니다.")
    }
}

inline fun B(
    lambda: () -> Unit
){
    lambda()
    println("B입니다.")
}

------------------------------

// 이렇게 변한다.
public final class DevGyuTestScreenKt {
   public static final void A() {
      int $i$f$B = 0;
      int var1 = 0;
      System.out.println("B 람다입니다.");
      System.out.println("B입니다.");
   }

   public static final void B(@NotNull Function0 lambda) {
      Intrinsics.checkNotNullParameter(lambda, "lambda");
      int $i$f$B = 0;
      lambda.invoke();
      System.out.println("B입니다.");
   }
}

inline 을 붙이니 이전과 달리 B의 코드를 복사하고, Lambda 함수 미생성 및 B를 호출하지 않는다.

inline 이 가진 단점

이러한 Inline 이 무조건 장점만 존재하는 것은 아니다.
Inline function 을 호출하는 곳이 많아지면 그만큼 복제하는 코드가 많아지므로 호출하는 함수나 클래스의 크기가 커지면서 용량 증가 및 캐시 효율이 떨어지게 된다.

또한 람다 내부에서 return 을 선언하는 경우 호출부의 스코프가 종료되는 상황이 발생하여 예상치 못한 버그가 발생 가능하다.

이러한 상황들을 방지하기 위해 inline keyword 를 사용할 때는 noinlinecrossinline 에 대해 알아야 한다.

crossinline keyword

Inline keyword 를 사용할때 비지역적 반환인 return 을 방지하여 버그 발생을 방지해준다.

코드를 하나 작성해보자.

fun A(){
    B{
        println("B 람다입니다.")
        return
    }
}

inline fun B(
    lambda: () -> Unit
){
    lambda()
    println("B입니다.")
}

위의 코드가 진행되는 경우를 살펴보자.

  1. B Lambda 가 실행되며 println("B 람다입니다.") 가 실행된다.
  2. return 되어 A() 가 종료되고 "B입니다." 는 출력되지 않는다.

inline 키워드가 존재하므로, 코드가 복사되었기 때문에 return 이 가리키는 방향은 A() 가 되므로 이렇게 실행되는 것은 당연하다.

이를 방지하고 싶다면 crossinline 을 사용하자.

이처럼 키워드를 추가로 설정하면 return 을 해당 위치에 사용할 수 없으므로 수정하라는 문구가 뜨게 된다.

noinline keyword

inline function 을 사용할때 inline 이 사용되면 안되는 Lambda 에 지정 가능하다. 이것을 사용하면 해당 람다 내부 코드가 복사되지 않고 inline 을 사용하지 않은 것처럼 된다.

이것을 사용하는 경우는 그리 많지 않겠지만, 사용해야하는 경우가 있기는 하다.

하나는 변수에 Lambda 에 저장할 때이다.
inline 키워드를 사용한 경우 Lambda 객체 생성이 되지 않는데, 없는 값을 변수에 넣으려고 하니 에러가 발생한다.

이런 경우 다음과 같이 noinline 을 붙여준다.

다만 이 경우 inline 기능을 포기하는 것이므로 이에 유의하자.

종합해서 사용해보기

inline function 안 Lambda 파라미터에 crossinline, noinline 을 각각 붙여줄 수 있다.
아무렇게나 구현하고 한 번 테스트를 진행해보자.

fun A(){
    B(
        inlineLambda = {},
        noinlineLambda = {},
        crossInlineLambda = {
            println("바보")
            return@B
        }
    )
}

inline fun B(
    inlineLambda: () -> Unit,
    noinline noinlineLambda: () -> Unit,
    crossinline crossInlineLambda: () -> Unit
){
    inlineLambda()
    noinlineLambda()
    crossInlineLambda()
}

컴파일 확인은 Android Studio 상단 - Tools - kotlin - show kotlin bytecode 를 보면 된다.

profile
안드로이드 개발자 Gyu 의 개발 블로그 !

0개의 댓글