🍀 Inline Function
Kotlin에서 고차함수를 사용하면 추가적인 메모리 할당 및 함수 호출로 Runtime Overhead가 발생한다.
inline function은 내부적으로 함수 내용을 호출되는 위치에 복사하며, Runtime overhead를 줄여준다.
inline을 사용하면 무의미한 객체 생성을 예방할 수 있다.
예시로 든 함수를 java로 decompile해보면 어떻게 될까 ?
fun main(args: Array<String>) {
val result = squareFunction(a = 3, function = { print("sson peace") })
println(result)
}
fun squareFunction(a: Int, function: () -> Unit): Int {
function()
return a * a
}
이렇게 function에 대한 객체를 생성하는 것을 확인 할 수 있는데, 이런 부분들이 성능을 저하시킬 수 있다.
public static final void main(@NotNull String[] args) {
Intrinsics.checkNotNullParameter(args, "args");
int result = squareFunction(3, (Function0)null.INSTANCE);
boolean var2 = false;
System.out.println(result);
}
public static final int squareFunction(int a, @NotNull Function0 function) {
Intrinsics.checkNotNullParameter(function, "function");
function.invoke();
return a * a;
}
그렇다면 inline function을 사용하고 decompile 해보자.
fun main(args: Array<String>) {
squareFunction(a = 3, function = { print("sson peace") })
}
inline fun squareFunction(a: Int, function: () -> Unit): Int {
function()
return a * a
}
public static final void main(@NotNull String[] args) {
Intrinsics.checkNotNullParameter(args, "args");
int a$iv = 3;
int $i$f$squareFunction = false;
int var3 = false;
String var4 = "sson peace";
boolean var5 = false;
System.out.print(var4);
int var10000 = a$iv * a$iv;
}
public static final int squareFunction(int a, @NotNull Function0 function) {
int $i$f$squareFunction = 0;
Intrinsics.checkNotNullParameter(function, "function");
function.invoke();
return a * a;
}
첫번째 예시와는 컴파일시에 다르게 객체를 생성하지 않고, 함수가 호출되는 곳에 함수 내부의 코드를 복사한다. 바이트코드의 양은 늘어나지만 추가적인 객체의 생성은 이루어지지 않는다.
이렇게 inline function은 일반 함수에 비해 성능이 좋다. 하지만 parameter로 받은 함수는 다른 함수로 전달되거나 참조될 수 없다.
inline fun squareFunction(a: Int, function: () -> Unit): Int {
testFunction(function)
return a * a
}
fun testFunction(function: () -> Unit) {
function()
}
// Error
// Illegal usage of inline-parameter 'function' in 'public inline fun squareFunction(a: Int, function: () -> Unit): Int defined in root package in file InlineTest.kt'. Add 'noinline' modifier to the parameter declaration
🌱 noinline
만약 인자별로 inline으로 처리되지 않게 하고 싶다면 noinline 키워드를 사용하면 된다.
fun main(args: Array<String>) {
squareFunction(a = 3, function = { print("sson peace ") }, function2 = { print("hello!") })
}
inline fun squareFunction(a: Int, function: () -> Unit, noinline function2: () -> Unit): Int {
function()
testFunction(function2)
return a * a
}
fun testFunction(function: () -> Unit) {
function()
}
이렇게 inline을 이용하면 런타임 오버헤드를 줄일 수 있지만,
너무 많은 바이트코드가 생성되지 않도록 적당한 함수를 잘 골라 사용해야할 것 같다!