빌드
- 개발자가 소스 코드를 작성 후 앱 설치 파일 APK 를 만들기까지의 실행 과정
리눅스에서의 빌드
- 소스 코드를 컴퓨터가 읽을 수 있는 기계어로 번역(*컴파일)하고, 내가 만든 소스 코드에서 사용하는 라이브러리와 연결해서 최종 실행 파일 형태로 만드는 것
- 컴파일(Compile) : 사람이 읽을 수 있는 형태의 소스 코드를 컴퓨터가 읽을 수 있는 형태의 기계어로 변환해 주는 과정
JVM 에서의 빌드
- JVM(Java Virtual Machine) : 자바는 OS 에 종속적이지 않다는 특징을 가지고 있다. OS 에 종속받지 않고 실행되기 위해서는 OS 위에서 자바를 실행할 수 있는 환경이 필요하다. JVM 은 자바 바이트 코드를 운영체제에 종속되지 않고 실행할 수 있도록 해주는 역할을 한다.
- .class 자바 클래스 파일 : *JVM 에서 실행 가능한 자바 바이트 코드(JVM 의 명령어 세트)를 포함하는 파일
- JAR(Java Archive) : 여러 개의 자바 클래스 파일과 클래스들이 이용하는 관련 리소스(텍스트, 그림 등) 및 메타데이터를 하나의 파일로 모아서 자바 플랫폼에 응용 소프트웨어나 라이브러리를 배포하기 위한 소프트웨어 패키지 파일 포맷
- Kotlin runtime : 코틀린 자체 표준 라이브러리 클래스와 자바 API 의 기능을 확장한 내용이 들어있다. 코틀린 컴파일러로 컴파일한 코드는 코틀린 런타임 라이브러리에 의존성을 가지기 때문에 애플리케이션을 배포할 때는 코틀린 런타임을 넣어 같이 배포한다.
Kotlin 과 Java 가 함께 있을 때의 컴파일 과정
- Kotlin 컴파일러가 Kotlin 코드를 컴파일해 .class 파일을 생성한다. 이 과정에서 Kotlin 코드가 참조하는 Java 코드가 함께 로딩되어 사용된다.
- Java 컴파일러가 Java 코드를 컴파일해 .class 파일을 생성한다. 이때 이미 Kotlin 이 컴파일한 .class 파일의 경로를 클래스 패스에 추가해 컴파일한다.
- 주의 : Kotlin 은 이미 컴파일된 단계에서 Java 컴파일이 이루어지기 때문에, Kotlin 코드에서 Java Annotation 프로세서로 생성되는 코드를 사용하면 문제가 발생한다.
안드로이드에서의 빌드
- 빌드 프로세스는 Gradle *빌드 도구가 수행한다.
- 빌드 도구 : 외부 라이브러리 추가 및 업데이트 등의 설정 시간을 단축시키고, 테스트 실행 및 호환성 체크까지 진행한다.
- 안드로이드에서 사용되는 빌드 도구는 maven, gradle 등이 있으며 구글에서는 gradle 의 사용을 권장하고 있다.
- Gradle 내부의 빌드 스크립트를 작성하여 앱의 의존성, 라이브러리, 리소스 파일, 빌드 설정 등을 진행한다.
- 빌드 도구 : 외부 라이브러리 추가 및 업데이트 등의 설정 시간을 단축시키고, 테스트 실행 및 호환성 체크까지 진행한다.
- 빌드 프로세스는 앱의 소스 코드와 빌드 스크립트를 결합하여 APK 파일을 생성한다.
1. 코틀린 컴파일러는 .kt 파일을 .class 바이트 코드 파일로 변환한다.
2. Android SDK 의 DX 도구를 사용하여 .class 파일들을 .dex 파일로 변환한다.
3. 안드로이드 리소스 패키징 도구(aapt)와 Gradle 사용하여 리소스 파일 및 외부 라이브러리 모듈을 .dex 파일과 함께 APK 파일로 패키징 한다.
4. APK 파일은 서명되어야 안드로이드 디바이스에서 실행될 수 있다. APK 파일에 서명하기 위해서는 디지털 인증서를 사용해야 한다. APK 파일에 서명하는 작업은 빌드 과정에서 Gradle 에 설정된 값에 따라 자동으로 수행한다.
APK 설치 및 실행
- 설치된 APK 는 안드로이드 런타임 과정을 따라 초기 JIT 방식을 활용하여 앱을 설치한 후, 이후 자주 사용하는 앱을 AOT 방식을 활용하여 컴파일하는 방식으로 진행된다.
- JIT(Just In Time) : 실행되는 시점에 필요한 코드만 컴파일하여 실행하는 방식으로, 런타임 중에 컴파일을 진행하여 런타임이 느리게 동작할 수 있다. 화면 전환 및 앱이 실행될 때마다 코드를 컴파일한다.
- AOT(Ahead Of Time) : 애플리케이션이 설치되는 시점에 코드를 컴파일하고 미리 캐시 하여 실행하는 방식으로, 애플리케이션 실행 속도가 빠르다.
- 각각의 컴파일 방식의 장단점을 해소하기 위해 이렇게 컴파일을 2번 진행한다.
- AOT 컴파일은 앱 설치 시 모든 코드를 미리 컴파일하기 때문에 실행 속도가 빠르지만, 컴파일된 파일이 디스크 공간을 많이 차지해 설치 가능한 앱의 수가 제한될 수 있다. 반면, JIT 컴파일은 실행 시 필요한 코드만 컴파일되기 때문에 초기 성능에 영향을 줄 수 있지만, 한 번 컴파일된 이후에는 AOT 와 비슷한 속도를 낼 수 있으며, 디스크 용량을 적게 차지한다.
안드로이드 런타임(Android Runtime, ART)
- 과거에 구글은 많은 사용자들이 사용하는 Java 를 기반으로 앱 개발을 지원했지만, 라이센스 문제와 메모리 효율성 문제로 인해 일반 JVM 환경 대신 Dalvik VM 을 선택하게 되었다.
Dalvik
- Android 2.1부터 5.1까지 사용되었던 런타임 환경
- JIT 컴파일러를 사용한다.
- 앱이 실행되는 순간 자주 사용되는 바이트 코드를 컴파일하여 Machine Code 로 변환 후 캐싱하여 RAM 에 올린다.
- 앱 실행 중 latency(지연 시간)가 발생한다.
- ART 에 기반에 설치 속도가 매우 빠르다.
- 컴파일이 빈번하게 일어나기에 배터리 소모 및 RAM 사용량이 높다.
- .dex 파일을 dexopt 툴을 이용해 .odex 파일로 변형한 뒤 DVM 에서 JIT 컴파일러로 .odex 파일을 기계어로 번역한다. 변환된 기계어는 RAM 에 올려지어 사용된다.
ART
- Android 4.4부터 현재까지 적용되는 런타임 환경
- AOT 컴파일러를 사용한다.
- 앱 설치 시 모든 코드를 Machine Code 로 컴파일하여 앱 패키지 안에 저장하기 때문에 설치 속도가 느리다.
- 앱 실행 시 컴파일을 하지 않아도 되기에 JIT 의 지연시간이 없다.
- 미리 컴파일 후 odex, elf 파일 등을 모두 모은 aot 파일을 저장하기 때문에 용량이 크다.
- .dex 파일을 dex2oat 툴을 이용해 .dex -> .odex -> .oat 파일로 변형한 뒤 OAT 컴파일러로 .oat 파일을 기계어로 번역한다.
- .oat 파일은 .dex 파일 + .odex 파일 + elf 파일(실행 파일) 형식의 기계어를 포함하고 있어 용량이 크다.
MultiDex
- 안드로이드 플랫폼에서 애플리케이션을 실행하는 데 사용되는 *DEX 파일 형식의 *한계를 극복하기 위해 도입된 메커니즘
- DEX(Dalvik Executable) : 코틀린 컴파일러가 .kt 파일을 .class 자바 바이트 코드로 변환한 후, 이 변환된 .class 파일들을 하나로 합쳐 생성한 실행 파일
- 한계 : 엡에 API 20 이하 minSdk 가 있고, 앱과 앱이 참조하는 라이브러리에서 메서드가 65,536(64K)개를 초과하면 앱이 Android 빌드 아키텍처의 제한에 도달했음을 나타내는 빌드 오류가 발생한다.
- 즉, 단일 DEX 바이트 코드 파일 내에서 참조할 수 있는 메서드의 총 개수를 초과하였다.
- Multidex 를 사용하면 애플리케이션이 두 개 이상의 DEX 파일을 가질 수 있다. 이를 통해 애플리케이션에 더 많은 메서드를 포함할 수 있으므로 메서드 수 제한이 방지된다.
- 기본 DEX 파일에 어떤 클래스를 포함하고 보조 DEX 파일에 어떤 클래스를 포함할지에 대한 복잡한 결정은 빌드 시스템에서 이루어지므로, 멀티덱스 구성에는 상당한 빌드 시간이 소요될 수 있다. 일반적으로 멀티덱스를 사용하는 증분 빌드는 시간이 더 걸리며, 개발 프로세스를 지연시킬 가능성이 있다.
- 더 긴 증분 빌드 시간을 완화하려면 사전 덱싱을 사용하여 빌드 간에 Multidex 출력을 재사용해야 한다. 사전 덱싱을 사용하려면 Android 5.0 이상에서만 사용할 수 있는 ART 형식이 필요하다.
- 64K 개 이상의 메서드 참조를 사용하도록 앱을 구성하기 전에 앱 코드가 호출하는 참조의 총 개수를 줄이는 단계를 먼저 진행한다.
- 앱의 직접 종속 항목과 전이 종속 항목 검토 : 앱에 포함되는 큰 라이브러리 종속 항목이 앱에 추가되는 코드 양을 초과하는지 고려한다.
- R8 로 사용되지 않는 코드 삭제 : 코드 축소를 활성화하여 출시 빌드에서 R8 을 실행한다. 축소를 활성화하면 사용되지 않는 코드와 리소스를 APK 에 포함하지 않을 수 있다.
- Android 5.0(API 수준 21) 이전의 플랫폼 버전에서는 앱 코드를 실행하기 위해 Dalvik 런타임을 사용한다. 기본적으로 Dalvik 에서는 APK 당 하나의 classes.dex 바이트 코드 파일로 앱을 제한한다. 이 제한을 우회하려면 *멀티덱스 라이브러리를 사용해야 한다.
- 이제 앱을 빌드할 때 Android 빌드 도구는 기본 DEX 파일(classes.dex)과 보조 DEX 파일(classes2.dex, calsses3.dex 등)을 필요에 따라 구성한다. 그 후 빌드 시스템이 모든 DEX 파일을 APK 로 패키징한다.
- 런타임에서는 기본 classes.dex 파일만 검색하는 대신, 멀티덱스 API 는 특별한 클래스 로더를 사용하여 메서드에서 사용할 수 있는 모든 DEX 파일을 검색한다.
- 이제 앱을 빌드할 때 Android 빌드 도구는 기본 DEX 파일(classes.dex)과 보조 DEX 파일(classes2.dex, calsses3.dex 등)을 필요에 따라 구성한다. 그 후 빌드 시스템이 모든 DEX 파일을 APK 로 패키징한다.
- Android 5.0(API 수준 21) 이상에서는 ART 런타임을 사용한다. 기본적으로 ART 는 APK 파일에서 여러 개의 DEX 파일을 로드하는 것을 지원한다. 앱 설치 시 사전 컴파일을 실행하여 classesN.dex 파일을 스캔하고 Android 기기에서 실행할 수 있는 단일 OAT 파일로 컴파일한다.
- 즉, minSdkVersion 이 21 이상이라면 멀티덱스가 기본적으로 사용 설정되며 멀티덱스 라이브러리가 필요하지 않다.
'안드로이드 > Android' 카테고리의 다른 글
[CS] 응집도(Cohesion)와 결합도(Coupling) (0) | 2024.12.08 |
---|---|
[Android] 이미지 최적화(로드 개선) (0) | 2024.11.12 |
[Android] Image Loader Library (0) | 2024.11.11 |