본문 바로가기

Android/Basic

[Android: CS] Dalvik vs ART

ART(Anroid Run Time)는 Android 4.4(Api 19)에서 처음으로 등장했으며, 해당 버전에서는 Dalvik과 함께 선택적으로 사용이 가능했다.
하지만 Android 5.0(Api 21) 이상 버전에서는 ART가 기본 런타임 환경으로 자리잡았다.

두가지 방식의 가장 큰 차이점은 컴파일 방식이다.

Dalvik은 JIT(Just-In-Time) 방식을 사용하고, ART는 AOT(Ahead-Of-Time) 방식을 사용(Android 7부터는 AOT와 JIT의 조합)한다.

두 방식을 간략하게 살펴보면 다음과 같다.

JIT(Jus-In-Time)

  • 앱 실행 시 컴파일
  • 설치 시 컴파일을 하지 않기 때문에 AOT보다 설치 속도가 빠르다.
  • 실행 시 컴파일을 하기 때문에 AOT에 비해 실행 속도가 느림.
  • 용량이 작다.

AOT(Ahead-Of-Time)

  • 앱 설치 시 컴파일
  • 설치 시 컴파일을 완료하기 때문에 JIT에 비해 설치 속도가 느리다.
  • 실행 시 컴파일을 하지 않기 때문에 JIT에 비해 실행 속도가 빠름.
  • 용량이 크다. (JIT에서 실행 시 컴파일하는 것을 미리 컴파일하여 가지고 있기 때문이다.)

그렇다면, 왜 JIT와 AOT에 이러한 차이가 있으며, 어떤 이유로 Dalvik은 JIT를 쓰고 ART는 AOT를 사용하는 걸까?

DVM(Dalvik Virtual Machine)

Dalvik은 Virtual Machine(가상머신)이다. 그래서 Dalvik Virtual Machine을 줄여 DVM이라고 한다.

코틀린이 JVM에서 작동함에도 불구하고, DVM을 사용하는 이유는 라이선스 문제나 메모리 효율성 등의 이유가 있다.
하지만, JVM과 DVM 모두 Java를 사용한 가상머신이기 때문에 비슷한 특성을 가지고 있다.

다음은 Java의 컴파일 과정이다.

Java는 컴파일러를 통해 바이트코드를 생성하는 과정까지는 컴파일러 언어의 특징을 가진다.
하지만 바이트코드는 기계어(Machine Code)가 아니다. 즉, 바이트코드는 특정 플랫폼에 종속된 것이 아니며 가상머신을 위한 코드일 뿐이다.
따라서 가상머신은 인터프리터를 통해 기계어로 해석되는 과정이 필요하다. 이러한 과정은 인터프리터 언어의 특징이라고 할 수 있다.

JIT(Just-In-Time) Compiler

호환성을 위한 가상머신의 특성으로 인해 Java는 실행 속도가 느리다. 이런 단점을 보완하기 위해서 JIT 컴파일러가 도입되었다.

JIT 컴파일러의 역할은 프로그램 실행 시 자주 사용되는 바이트코드를 미리 기계어로 해석해 놓는 것이다. 그러면 다시 해당 바이트코드가 사용될 때 재해석을 할 필요가 없어 속도가 향상된다.

초기 DVM에는 JIT이 없었고 Android 2.2 Froyo부터 적용되었다. DVM의 JIT은 Trace 방식의 JIT이다.
Trace JIT은 Threshold를 초과하면 바이트코드를 기계어로 해석한다. 즉, 어떤 구간(if문, for문)이 특정 횟수 이상 반복되면 컴파일한다.

컴파일은 별도의 컴파일 쓰레드에 의해서 진행된다. 컴파일이 완료되면 해석된 기계어를 Translation Cache에 저장한다.
이러한 과정을 도식화하면 아래와 같다.

이러한 방법으로 자주 사용하는 부분에 대해 미리 컴파일하여 기계어로 해석해 놓기 때문에, 실행 성능을 향상 시키긴 했지만 AOT보다는 느리다. AOT는 설치 시점에 컴파일을 완료하여 기계어로 해석이 끝났기 때문이다. 따라서 실행 시, 해석 과정 없이 곧바로 기계어로 실행된다.

ART(Android RunTime) & AOT(Ahead-Of-Time)

DVM은 앱을 실행할 때마다 인터프리터를 통해 해석하거나 JIT컴파일러를 통해 부분적으로 해석한 기계어를 저장 및 실행한다.
하지만 ART는 AOT 컴파일러를 사용하여 앱을 설치할 때 바이트 코드를 기계어로 해석 완료한다. 따라서 설치하는 시간은 오래걸리지만, 일단 설치를 끝마치면 실행할 때는 빠르다는 장점이 있다.

ART를 DVM과 JVM의 컴파일 과정과 함께 비교해보면 위 그림과 같다.

상기 이미지에서 눈여겨 볼 부분은 AOT 컴파일러가 APK를 설치할 때 기계어로 해석한다는 것이다. 이때 사용되는 것은 APK에 포함된 Dalvik에서 사용하는 dex파일이다.
사실 DVM도 dex파일을 그대로 사용하는 것이 아니라 odex파일로 변경하여 사용한다.

dexopt & dex2oat

dex 파일이 변경되는 과정을 좀 더 자세히 알아보기 위해서 다음 그림을 살펴보겠다.

Dalvik은 dexopt라는 툴을 통해서 dex파일을 최적화한 odex(opimized dex)라는 파일을 만든다.
odex는 특정 기기의 시스템에 최적화된 코드이기 때문에 다른 기기에서 사용할 수 없다.
DVM은 이 odex파일을 앱 실행 시 기계어로 해석한다.

ART은 AOT 컴파일 시 dex2oat라는 툴을 사용해서 dex파일을 odex로 변경한 후, 다시 oat파일로 변경한다.
oat파일을 elf파일 형식의 기계어를 포함하는 파일이다.
elf파일은 간단히 말하면 실행파일(executable file)이다.

ART의 단점으로는 용량이 크다는 점이 있는데, oat파일이 dex/odex파일을 포함하고 있어서 용량이 큰 것이다.