모바일 개발의 Runtime: 런타임 시스템이란 무엇이며 어떻게 작동하는가

저자: IT Sectr 게시일: 2026-05-17 읽는 시간: 9 분

Runtime은 모바일 애플리케이션 코드의 실행을 관리하는 소프트웨어 계층입니다. 메모리를 할당하고, 예외를 처리하고, 가비지 컬렉션을 실행하고, 메서드 호출을 디스패치합니다. 런타임 없이는 어떤 애플리케이션도 실행될 수 없습니다. 컴파일된 코드와 운영 체제 사이의 중간 계층입니다. Android Developer Documentation, 2025에 따르면, 런타임 환경은 성능과 호환성을 결정하는 플랫폼의 핵심 요소입니다.

핵심 포인트

  • Runtime은 모바일 애플리케이션의 바이트코드 또는 기계어 코드를 실행하는 소프트웨어 환경입니다.
  • ART(Android Runtime)는 AOT 컴파일을 사용하며 Android 5.0부터 Dalvik을 대체했습니다.
  • Objective-C Runtime은 iOS에서 동적 메서드 디스패치와 메시지 패싱을 제공합니다.
  • JIT 컴파일은 애플리케이션 실행 중에 바이트코드를 기계어 코드로 직접 컴파일합니다.
  • ARM64 Runtime은 64비트 ARM 프로세서용 최적화 코드가 실행되는 하드웨어 수준입니다.

모바일 개발에서 Runtime이란?

Runtime은 프로그램 시작 후 실행을 보장하는 인프라입니다. 모바일 개발의 맥락에서 런타임에는 클래스 로더, 메모리 할당자, 가비지 컬렉터, 메서드 디스패처 및 예외 처리기가 포함됩니다. 이 중간 계층이 없으면 운영 체제는 Dalvik 바이트코드나 Objective-C 메시지를 실행할 수 없습니다.

모바일 플랫폼은 서로 다른 런타임 구현을 사용합니다. Android는 하이브리드 AOT/JIT 컴파일과 함께 ART(Android Runtime)를 사용합니다. iOS는 메시지 패싱 및 SEL 식별자 기반의 동적 시스템인 Objective-C Runtime을 사용합니다. 두 접근 방식 모두 동일한 문제를 해결합니다. 특정 장치에서 개발자의 코드를 최대 성능으로 실행하는 것입니다.

Google I/O 2024에 따르면, Android Runtime은 전 세계 장치에서 하루 100억 개 이상의 메서드를 처리합니다. Runtime 성능은 애플리케이션 시작 속도, 애니메이션의 부드러움 및 배터리 소모에 직접적인 영향을 미칩니다. 모든 메서드 호출, 모든 메모리 할당 및 모든 가비지 컬렉션 주기는 런타임 계층을 통과합니다.

Runtime 시스템: 구성 요소

Runtime 시스템에는 클래스 로더, 메모리 관리자, 인터프리터 또는 컴파일러, 메서드 디스패처 및 보안 시스템의 다섯 가지 주요 구성 요소가 포함됩니다. 각 구성 요소는 코드 실행 프로세스에서 엄격하게 정의된 기능을 수행합니다.

클래스 로더 및 검증

사용자가 애플리케이션을 시작하면 ClassLoader가 DEX 파일(Android) 또는 Mach-O 바이너리(iOS)를 RAM에 로드합니다. Android에서 이 단계에는 바이트코드 검증이 포함됩니다. 런타임은 코드에 안전하지 않은 명령이 포함되어 있지 않은지, 배열 경계를 벗어나지 않는지, 유형을 준수하는지 확인합니다. 검증은 악성 코드 실행을 방지하는 중요한 보안 단계입니다.

메모리 관리자 및 가비지 컬렉터

메모리 관리자는 객체의 메모리를 할당하고 해제합니다. Android ART에서는 세대별 수집(generational collection)을 사용하는 동시 가비지 컬렉터가 사용됩니다. 젊은 객체는 더 자주 확인되고, 오래된 객체는 덜 자주 확인됩니다. Objective-C Runtime은 ARC(자동 참조 카운팅)를 사용하며, 컴파일러가 자동으로 retain/release 호출을 삽입합니다.

메서드 디스패처 및 가상 테이블

메서드 디스패처는 어떤 메서드 구현이 호출될지 결정합니다. 정적 언어(Kotlin, Swift)에서는 vtable(가상 메서드 테이블)을 통해 디스패치가 수행됩니다. 동적 언어(Objective-C)에서는 메시지가 objc_msgSend를 통과하여 클래스와 그 슈퍼클래스에서 구현을 찾습니다. 결과는 반복 호출을 가속화하기 위해 method cache에 캐시됩니다.

Android에서 ART 작동 방식

Android Runtime(ART)은 Android 애플리케이션의 DEX 바이트코드를 실행하는 가상 머신입니다. ART는 Android 5.0 Lollipop에서 Dalvik을 대체하고 AOT 컴파일을 도입했습니다. 애플리케이션은 설치 중에 한 번 기계어 코드로 컴파일됩니다. 이렇게 하면 매 시작 시 JIT 컴파일의 오버헤드가 제거되었습니다.

Android 7.0 Nougat부터 ART는 하이브리드 접근 방식을 사용합니다. 설치 중에 JIT 컴파일은 자주 사용되는 메서드(hot methods)에 대해서만 수행되고, 나머지 코드는 해석됩니다. 백그라운드 프로세스(프로필 기반 최적화)는 가장 자주 호출되는 메서드를 분석하고 장치 유휴 시간 동안 AOT 컴파일합니다. 이를 통해 높은 성능을 보장하면서 설치 시간을 단축합니다.

ART에는 DEX 파일을 ARM64 기계어 코드가 포함된 ELF 바이너리로 변환하는 AOT 컴파일러(dex2oat)도 포함되어 있습니다. 컴파일은 세 가지 최적화 수준으로 수행됩니다: quicken(빠름), optimize(중간), everything(전체). 기본적으로 Android는 컴파일 속도와 코드 성능 간의 균형을 유지하는 optimize를 사용합니다.

kotlin
class RuntimeExample {
    fun measureExecutionTime() {
        val start = System.nanoTime()
        // ART에 의해 컴파일된 메서드 호출
        processData()
        val end = System.nanoTime()
        println("실행 시간: ${end - start} ns")
    }
}

위 예제에서 System.nanoTime()은 네이티브 메서드로, 해당 호출은 ART 런타임을 통해 Linux 커널로 디스패치됩니다. ART는 Kotlin 바이트코드를 ARM64 명령어로 변환하여 장치의 프로세서가 실행합니다. 이 프로세스는 개발자에게 투명하게 이루어지지만, 그 최적화는 Android Platform 팀의 핵심 작업입니다.

프로필 기반 최적화(PGO)

프로필 기반 최적화는 메서드 사용 프로필을 수집하는 ART 메커니즘입니다. profiles/.primary.prof 파일에는 AOT 컴파일되는 hot 메서드 목록이 포함되어 있습니다. Android Performance Team에 따르면, PGO는 프로필이 축적된 후 며칠 사용 후 애플리케이션 시작을 15~30% 가속화합니다.

개발자는 Gradle 프로젝트에서 베이스라인 프로필을 활성화할 수 있습니다. 이는 설치 직후 어떤 메서드를 AOT 컴파일할지 ART에 알리는 수동 어노테이션입니다. 베이스라인 프로필은 백그라운드 프로파일링을 기다리지 않고 첫 시작을 40% 단축합니다.

iOS에서 Objective-C Runtime 작동 방식

Objective-C Runtime은 iOS 및 macOS에서 Objective-C 코드 실행을 제공하는 동적 라이브러리입니다. 그 핵심은 메시지 패싱을 구현하는 objc_msgSend 함수입니다. 직접적인 메서드 호출 대신 객체가 선택자(selector)와 함께 메시지를 보내면, 런타임이 어떤 구현을 실행할지 결정합니다.

각 Objective-C 객체에는 클래스에 대한 isa 포인터가 포함되어 있으며, 클래스에는 선택자(SEL)를 구현(IMP)에 매핑하는 디스패치 테이블이 있습니다. 메서드가 호출되면 objc_msgSend는 체인(클래스 → 슈퍼클래스 → NSObject)을 따라 IMP를 찾을 때까지 탐색합니다. 구현을 찾을 수 없으면 런타임이 포워딩 메커니즘을 호출하여 메시지를 가로채거나 예외를 생성할 수 있습니다.

Objective-C Runtime은 메서드 스위즐링도 지원합니다. 런타임에 기존 선택자의 IMP를 대체하는 것입니다. 이는 AOP 라이브러리 및 모니터링 도구에서 사용되는 강력한 메커니즘이지만, 전체 애플리케이션에 미치는 영향 때문에 주의가 필요합니다.

objective-c
@interface RuntimeDemo : NSObject
- (void)printClassInfo;
@end

@implementation RuntimeDemo
- (void)printClassInfo {
    // objc_getClass — 런타임 함수
    Class cls = objc_getClass("RuntimeDemo");
    unsigned int count;
    Method *methods = class_copyMethodList(cls, &count);
    NSLog("메서드 수: %d", count);
}
@end

코드는 Objective-C Runtime API에 대한 직접 액세스를 보여줍니다. objc_getClass는 이름으로 클래스 객체를 가져오고, class_copyMethodList는 모든 메서드 목록을 검색합니다. 이것은 실행 중인 리플렉션입니다. 런타임에 클래스 메타데이터에 액세스하는 것입니다. 이 접근 방식은 XCTest에서 동적 테스트 등록에 사용됩니다.

isa 포인터 및 태그된 포인터

isa 포인터는 각 객체의 처음 8바이트에 저장된 객체 클래스에 대한 포인터입니다. iOS 12부터 Apple은 최적화를 위해 isa 스위즐링을 도입했습니다. isa의 하위 비트는 객체 상태에 대한 추가 정보를 인코딩합니다. 태그된 포인터는 또 다른 최적화로, 최대 60비트 값(NSNumber, NSDate)이 힙에 객체를 할당하지 않고 포인터에 직접 저장됩니다. 이렇게 하면 메모리 관리자 부하가 30% 감소합니다.

JIT와 AOT 컴파일: 접근 방식 비교

JIT(Just-In-Time)와 AOT(Ahead-Of-Time)는 바이트코드를 기계어 코드로 컴파일하는 두 가지 접근 방식입니다. JIT는 애플리케이션 실행 중에 코드를 컴파일하고, 핫스팟을 분석하여 즉석에서 최적화합니다. AOT는 모든 코드를 미리 컴파일합니다. 애플리케이션 설치 중 또는 개발자 측에서 수행합니다.

특성JITAOT
컴파일 시간실행 중설치/빌드 중
APK/IPA 크기더 작음(바이트코드만)더 큼(기계어 코드)
시작 속도더 낮음(컴파일 필요)더 높음(코드 준비됨)
장치별 최적화예(적응형)제한적(일반형)
RAM 소비더 높음(메모리 내 컴파일러)더 낮음

ART 하이브리드 접근 방식(Android 7+)이 최적으로 간주됩니다. 애플리케이션은 드물게 호출되는 메서드에 인터프리터를, hot 메서드에 JIT를, 프로필 기반 최적화의 메서드에 AOT를 사용합니다. 반대로 iOS는 LLVM을 통한 엄격한 AOT를 사용합니다. Swift와 Objective-C는 Xcode의 빌드 단계에서 기계어 코드로 컴파일됩니다.

Apple Developer Documentation, 2024에 따르면, Swift 런타임은 애플리케이션 크기에 약 15MB를 추가합니다. Flutter는 자체 Dart VM을 사용하며, JIT 컴파일은 핫 리로드를 위해 디버그 모드에서 작동하고, AOT는 최대 성능을 위해 릴리스 모드에서 작동합니다. React Native는 Hermes를 사용합니다. AOT 컴파일이 포함된 JavaScript 엔진으로 시작 시간을 50% 단축합니다.

ARM64 Runtime 및 기계어 코드

ARM64 Runtime은 기계어 코드가 장치의 프로세서와 상호 작용하는 수준입니다. 대부분의 최신 모바일 장치는 ARM64(aarch64) 프로세서에서 실행됩니다. 런타임은 바이트코드 또는 네이티브 호출을 CPU가 실행하는 ARM64 명령어로 변환합니다.

런타임에서 사용하는 주요 ARM64 레지스터: x0~x7(함수 매개변수), x8(간접 결과), x30(반환 주소), sp(스택 포인터), fp(프레임 포인터). ART는 ARM64 Procedure Call Standard를 따르는 코드를 생성합니다. 모든 메서드 호출은 프로세서 아키텍처에 의해 정의된 프로토콜을 통과합니다.

ARM64 ABI를 이해하는 것은 성능 최적화에 중요합니다. 인라인 캐싱, 분기 예측 및 메모리 내 코드 정렬은 런타임 속도에 직접적인 영향을 미칩니다. 프로파일링 도구(Android Studio Profiler, Instruments)는 어떤 코드 섹션이 런타임에서 가장 많은 시간을 소비하는지 보여줍니다. 이를 최적화하면 가장 큰 개선 효과를 얻을 수 있습니다.

cpp
// ART에 의해 생성된 ARM64 어셈블리 예제
// 두 개의 매개변수가 있는 메서드 호출

mov    x0, x23            // self(this)
mov    x1, x24            // param1
mov    x2, x25            // param2
bl     methodEntryPoint   // 런타임을 통한 호출
str    x0, [sp, #8]      // 결과 저장

이 예제에서 ARM64 명령어 mov는 레지스터 x0~x2에 인수를 전달하고, bl은 메서드 진입점을 호출하며, str은 반환 값을 저장합니다. 런타임은 모든 메서드 호출에 대해 이러한 명령어를 생성하고, 디버추얼라이제이션(devirtualization) 및 인라이닝(inlining)을 통해 시퀀스를 최적화합니다.

런타임이 성능에 미치는 영향

런타임 오버헤드는 동적 디스패치의 불가피한 비용입니다. 런타임을 통한 각 메서드 호출에는 디스패치 테이블에서 구현 검색, 유형 확인, IMP 호출 및 결과 반환이 필요합니다. 측정에 따르면 런타임은 Objective-C에서 호출당 10~50ns, ART에서 5~20ns를 추가합니다.

오버헤드를 줄이기 위해 개발자는 모노모픽 인라이닝(ART) 및 메서드 캐싱(Objective-C)을 사용합니다. Kotlin/Native 및 Swift는 직접 ARM64로 컴파일되어 런타임 계층을 완전히 제거하지만, 리플렉션, 스위즐링, 동적 클래스 로딩과 같은 동적 기능을 잃게 됩니다.

자주 묻는 질문

Runtime과 SDK의 차이점은 무엇인가요?

SDK(Software Development Kit)는 애플리케이션 개발을 위한 도구 모음(컴파일러, 라이브러리, 유틸리티)입니다. Runtime은 이미 개발된 애플리케이션이 장치에서 실행되는 환경입니다. 개발자에게는 SDK가 필요하고, 사용자에게는 런타임이 필요합니다.

모바일 애플리케이션에서 Runtime을 교체할 수 있나요?

아니요. 런타임은 운영 체제의 일부이며 사용자가 교체할 수 없습니다. ART는 Android Framework에 내장되어 있고, Objective-C Runtime은 iOS에 내장되어 있습니다. 개발자는 언어를 선택하거나(Kotlin/Native, 런타임 없음) Flutter의 Dart VM과 같은 가상 머신을 사용할 수 있습니다.

Runtime이 배터리 소모에 영향을 미치나요?

네, 런타임은 에너지 소모에 영향을 미칩니다. ART 및 Swift 런타임의 가비지 컬렉션은 CPU를 사용하여 배터리 소모를 증가시킵니다. iOS의 동시 GC 및 태그된 포인터와 같은 최적화는 런타임이 배터리에 미치는 영향을 20~30% 감소시킵니다.

런타임 오류란 무엇이며 어떻게 잡나요?

런타임 오류는 실행 중에 발생하는 오류입니다. 널 포인터 예외, 배열 범위 초과, 0으로 나누기 등이 있습니다. 컴파일 타임 오류와 달리 빌드 중에 감지되지 않습니다. try-catch 블록 또는 크래시 리포팅(Firebase Crashlytics, Sentry)을 통해 잡을 수 있습니다.

Swift 런타임과 Objective-C Runtime의 차이점은 무엇인가요?

Swift 런타임은 Objective-C보다 가볍습니다. 기본적으로 동적 디스패치를 지원하지 않으며, 힙 할당 없이 값 유형(struct)을 사용하고 메시지 포워딩이 없습니다. Swift 메서드는 @objc dynamic으로 표시되지 않은 경우 vtable을 통해 직접 호출됩니다. 이는 벤치마크에서 최대 5배의 속도 향상을 제공합니다.

요약

  • Runtime은 메모리, 메서드 및 코드 보안을 관리하는 실행 환경입니다.
  • ART(Android)는 최적의 성능을 위해 프로필 기반 최적화를 갖춘 하이브리드 JIT/AOT 접근 방식을 사용합니다.
  • Objective-C Runtime은 objc_msgSend 및 디스패치 테이블을 통한 메시지 패싱을 기반으로 합니다.
  • JIT는 즉석에서 코드를 컴파일하고 장치에 적응하며, AOT는 빠른 시작을 위해 미리 컴파일합니다.
  • ARM64 Runtime은 최신 프로세서에서 기계어 코드를 실행하는 하드웨어 계층입니다.
  • 런타임 오버헤드는 메서드 호출당 5~50ns이며 인라이닝 및 캐싱을 통해 최소화됩니다.
  • 성능 최적화, 디버깅 및 애플리케이션 아키텍처 선택을 위해 런타임 이해가 필요합니다.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기