성능 분석으로 알아보는 Java와 Kotlin의 static function

January 6, 2025 강건구 조회수 2,203

여러 클래스에서 쉽게 접근하기 위해 Java에 static function을 사용합니다. 이를 Kotlin에서는 다양한 방법으로 static function을 대체할 수 있습니다. 두 방식의 차이점을 알아보고, 각각의 성능을 직접 분석해보았습니다

Java -> Kotlin 리펙토링

Android App 개발을 위한 언어로 가장 많이 사용하는 언어가 Java와 Kotlin 입니다. 각각의 언어마다 장단점은 뚜렷하기에 어떤 언어를 선택할지는 어려운 일입니다. 제가 회사에서 맡고 있는 Android App은 Java를 사용해 개발해왔습니다. 하지만 Kotlin은 간결하면서도 강력한 기능을 제공하며, Null 안정성, 함수형 프로그래밍 지원 등의 특징을 가지고 있습니다. 또한, Java와의 상호 운용성이 뛰어나기 때문에 기존 Java 프로젝트에서도 쉽게 적용할 수 있습니다.


이러한 이유로 많은 Android 개발자가 Kotlin으로 언어를 변경해 개발하고 있습니다. 저 역시 Kotlin이 주는 간단함과 명확함이 마음에 들어 파트에서 진행하는 Android App 개발을 Java에서 Kotlin으로 리팩토링하고 있습니다.

성능 분석의 필요성

Java의 static method를 Kotlin 문법으로 바꿔야 하는 상황이 있었습니다. Kotlin에서 Java의 static method를 대체하는 방법으로는 아래 2 가지가 있습니다.

  1. Object method

  2. Top-Level Functions


Java static method를 Kotlin 문법으로 아래와 같이 바꿀 수 있습니다.




이 중 Object를 이용한 방식을 채택해 개발하고 있었습니다. Static method를 역할별로 나눠 모듈화 할 수 있다는 장점으로 해당 방식을 채택했습니다. 하지만, Java의 static method와 Kotlin의 Object를 이용한 방식은 실제 호출 방식이 상이하다는 것을 알게 되었습니다.  이렇게 되면 둘 간의 성능 차이가 존재하고, Java의 static method 방식의 성능이 유의미할 정도로 훨씬 좋다면, static method는 java로 놔두는 것도 좋은 방법일 것 같다고 느꼈습니다. 그래서 직접 테스트를 해보며 성능 분석을 해보게 되었습니다.

Benchmark 툴

성능 분석을 위한 benchmark 툴로, 안드로이드에서 공식적으로 제공하는 툴이 있습니다. 종류로 Microbenchmark와 Macrobenchmark가 있습니다. 저는 필요한 부분만 소규모로 분석하면 되기에 Microbenchmark를 사용했습니다.


세팅과 사용법을 확인하려면 아래 사이트를 참고해주시면 좋겠습니다.

 - https://developer.android.com/topic/performance/benchmarking/microbenchmark-write?hl=ko

테스트

테스트 해 볼 상황은 아래 두 가지입니다.


  1. Kotlin class에서 Java static method 호출

  2.Kotlin class에서 Object method 호출


코드는 적은 연산을 하는 quickAdd 메서드와 많은 연산을 하는 slowAdd 메서드로, 각각 1 개씩 준비했습니다.



Java static method



Kotlin Object


두 코드를 각각 아래와 같이 테스트 한 뒤, Microbenchmark로 성능 분석을 했습니다.

  1. quickAdd : 10000번 돌려 테스트

  2. slowAdd : 100번 돌려 테스트


결과

테스트 결과, 아래와 같이 나왔습니다.





분석

적은 연산을 하는 함수에서는 성능의 차이가 미미하지만, 많은 연산을 하는 함수에서는 Kotlin Object 방식이 Java static method 방식보다 약 8.4% 성능 향상이 있었습니다.


1) Bytecode 차이

Bytecode를 확인하면 JVM 상에서 해당 코드를 어떻게 호출하는지 파악할 수 있습니다. 두 코드의 bytecode를 각각 확인해보면 호출 방식이 다르단 것을 확인할 수 있습니다.

  1. Java static method : INVOKESTATIC

  2. Kotlin Object : INVOKEVIRTUAL


 - INVOKESTATIC

  1. JVM 바이트 코드에서 invokestatic 명령어로 호출됨

  2. 클래스의 method area에 직접 접근하여 메서드를 실행함

  3.이 과정은 인스턴스 메서드 호출보다 빠름


 - INVOKEVIRTUAL

  1. JVM 바이트 코드에서 invokevirtual 또는 invokespecial 명령어로 호출됨

  2. 메모리에서 객체의 인스턴스를 참조한 후 메서드를 호출하는 과정이 필요하므로 INVOKESTATIC에 비해 비효율적


이렇게만 놓고 분석해봤을 땐, Java static method가 더 효율적이여야 하지만, 실제 성능은 그렇지 않았습니다.


2) JIT 컴파일러 최적화

JIT 컴파일러가 효율적으로 이 코드를 최적화하는 방법에 따라 차이가 날 수 있습니다. 반복적으로 호출되는 부분을 컴파일러가 알아서 감지하고 최적화합니다.  Kotlin의 object는 JVM 힙에 저장되는 싱글톤 객체로 관리되며, 해당 객체의 메서드 호출은 JVM의 최적화 대상이 될 가능성이 높습니다. 반면, Java의 static 메서드는 클래스 로더와 직접적으로 관련되며, 클래스 로딩 시점과 초기화 과정에서 추가적인 메모리 접근 비용이 발생할 수 있습니다.


컴파일러가 Kotlin의 Object를 단순화하여 인라이닝으로 사용해 더 좋은 성능이 나타난 것으로 보입니다.

결론

저희 프로젝트에서는 해당 메서드를 한 번의 라이프 사이클 안에서 반복적으로 여러 번 사용하는 부분은 적습니다. 그래서 두 방식 간의 큰 성능의 차이는 미미할 것으로 예상됩니다. 하지만 static method의 특성 상, 여러 곳에서 자주 쓰일 수 있는 함수입니다. 이러한 성능 차이로 인한 결과를 인지하고, 리팩토링 할 때 고려해 볼만한 가치가 있다고 생각합니다.


감사합니다.




저자

강건구

System Platform개발그룹(MX)

이메일 문의하기