백엔드 엔지니어가 코드 전반에 걸쳐 사용할 수 있는 유틸 함수를 만들고 있었습니다. 인라인 함수로 적용하고 싶어 inline
키워드를 붙였는데 아래와 같은 경고 문구가 발생했습니다.
Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types
인라인 함수로 만들었을 때 예상되는 성능 향상이 거의 없을 것이라는 경고문이었습니다. 인라인 함수는 함수를 파라미터로 받는 함수에서 가장 좋은 효과를 보일 것이라고 조언까지 해줬습니다.
실제로 함수를 파라미터로 받도록 설정하니 해당 경고문이 사라졌습니다. 왜 함수를 파라미터로 받는 함수가 인라인 함수로 만들었을 때 큰 효과를 보는지 궁금해 찾아보기로 했습니다.
함수를 인라이닝하게 되면 파라미터로 전달된 함수의 본문을 호출하는 쪽에 그대로 넣어주게 됩니다. 따라서 함수 호출을 위해 스택을 쌓고 호출이 종료되면 다시 복귀하는 동작을 하지 않아도 됩니다.
fun printMessage(lazyMessage: () -> Any?) {
println(lazyMessage())
}
fun main() {
printMessage { "TEMP" }
}
위와 같은 함수를 하나 정의하고 IntelliJ의 도움을 받아 java로 디컴파일 해보면 다음과 같은 코드가 나오게 됩니다.
public static final void printMessage(@NotNull Function0 lazyMessage) {
Intrinsics.checkNotNullParameter(lazyMessage, "lazyMessage");
Object var1 = lazyMessage.invoke();
System.out.println(var1);
}
public static final void main() { printMessage((Function0)null.INSTANCE); }
여기서 printMessage
함수를 인라인 함수로 만들면 java 코드가 다음과 같이 변하게 됩니다.
public static final void printMessage(@NotNull Function0 lazyMessage) {
int $i$fprintMessage = 0;
Intrinsics.checkNotNullParameter(lazyMessage, "lazyMessage");
Object var2 = lazyMessage.invoke();
System.out.println(var1);
}
public static final void main() {
int $i$fprintMessage = false;
int var1 = false;
String var2 = "TEMP";
System.out.println(var2);
}
printMessage
함수를 호출하기 위해 Function0
객체를 생성하지 없어졌습니다. 이로 인해 Function0
객체 생성 비용을 없앨 수 있게 되었습니다.
함수를 파라미터로 받는 함수를 반복적으로(자주) 호출하는 경우 inline
여부에 따라 성능 차이가 발생할 수 있습니다.
함수를 파라미터로 받지 않는 경우에는 함수 호출 전에 객체가 이미 생성되어 있고, 이 객체의 참조값을 넘겨주거나 값 복사를 통해 사용할 수 있기 때문에 상대적으로 얻게 되는 성능 향상이 미비하다고 경고 문구를 보여주는 것 같습니다.