iOS 메모리 관리 기초: Swift로 배우는 Compressed, Swapped, Resident 메모리

작성일 :

iOS 메모리 관리 기초: Swift로 배우는 Compressed, Swapped, Resident 메모리

들어가기

iOS 애플리케이션 개발에서 메모리 관리는 성능 최적화의 핵심 요소입니다. 메모리 누수(leak)와 같은 문제를 예방하려면 메모리 사용 패턴을 이해하고, 이를 관리하는 방법을 숙지해야 합니다. 이번 글에서는 Compressed 메모리, Swapped 메모리, Resident 메모리의 개념을 중심으로 iOS 메모리 관리 기초를 배워보겠습니다. 특히 Swift 언어를 사용하여 구현한 예제를 통해 실질적인 이해를 높이는데 주력하겠습니다.

메모리 타입: Compressed, Swapped, Resident

Compressed 메모리

Compressed 메모리는 메모리가 부족할 때 시스템이 메모리 페이지(page)를 압축하여 저장하는 방식을 말합니다. 이는 실제 물리적 메모리를 덜 사용하게 하여 더 많은 애플리케이션이 동시에 실행될 수 있도록 합니다. 예를 들어, 압축 전 1MB의 데이터를 압축하여 0.5MB로 줄일 수 있습니다.

압축은 CPU 사용량을 증가시키는 단점이 있지만, 메모리 부족 문제를 해결하는 유용한 방법입니다. Swift에서는 이러한 압축 메모리를 직접적으로 관리하진 않지만, iOS 시스템이 내부적으로 이를 활용하여 메모리 효율성을 증가시킵니다.

swift
if let compressedData = data.compressed(using: .lz4) {
    print("압축된 데이터 크기: \(compressedData.count) 바이트")
}

위 예제처럼 데이터를 압축하는 메소드를 사용할 수 있습니다. 하지만 이는 실제 Compressed 메모리와는 달리 데이터 압축을 수행하는 것임에 유의하세요.

Swapped 메모리

Swapped 메모리는 시스템 메모리가 부족할 때, 사용하지 않는 메모리 페이지를 디스크로 옮기는 과정을 말합니다. 이는 디스크 I/O 성능에 영향을 미칠 수 있으며, 과도한 스왑은 성능 저하를 초래할 수 있습니다.

iOS에서는 사용할 수 있는 물리적 메모리(ram)가 제한적이기 때문에, 스와핑을 통해 메모리 관리를 하기도 합니다. 하지만 iOS 시스템은 기본적으로 스왑을 되도록 피하려고 하며, 메모리 사용량이 많은 앱은 시스템에 의해 종료될 수 있습니다.

swift
let largeArray = [Int](repeating: 0, count: 1_000_000)
// 배열 'largeArray'가 큰 메모리 공간을 차지하며, 스왑 가능성을 증가시킵니다.

Resident 메모리

Resident 메모리는 시스템이 현재 실제 물리 메모리에 로드된 상태의 메모리 페이지를 의미합니다. 이 메모리 페이지는 언제든지 애플리케이션이 즉시 접근하여 사용할 수 있습니다. 따라서 Resident 메모리는 매우 빠른 접근 속도를 보장합니다.

swift
class MyObject {
    var data: [Int]
    init(size: Int) {
        data = [Int](repeating: 0, count: size)
    }
}

let myObject = MyObject(size: 10_000)
print("Resident 메모리 사용 예제")

위 예제에서 myObject는 Resident 메모리에 위치한 데이터를 가지고 있습니다. 이러한 데이터는 메모리에서 바로 접근할 수 있어 빠른 속도를 자랑합니다.

메모리 사용 최적화

메모리 관리를 효율적으로 하기 위해 iOS 개발자는 다음 몇 가지 기법을 활용할 수 있습니다.

ARC (Automatic Reference Counting)

ARC는 Swift의 메모리 관리 방식으로, 객체의 생명 주기를 자동으로 관리합니다. ARC는 객체에 대한 참조(reference) 수를 추적하여 필요 없을 때 이를 자동으로 해제(deallocate)합니다.

swift
class Person {
    let name: String
    init(name: String) {
        self.name = name
    }
}

var john: Person? = Person(name: "John")
var jane: Person? = Person(name: "Jane")

john = nil // john 객체는 메모리에서 해제됩니다.
jane = nil // jane 객체도 메모리에서 해제됩니다.

메모리 누수 탐지

메모리 누수를 예방하려면 Xcode Instruments의 'Leaks' 도구를 사용하여 메모리 사용을 모니터링할 수 있습니다. 이를 통해 애플리케이션의 메모리 사용 패턴을 분석하고, 누수를 유발하는 코드를 수정할 수 있습니다.

swift
// Leaks 도구로 메모리 누수를 확인할 시, 잘못된 코드 예시
class NetworkManager {
    var completionHandler: (() -> Void)?

    func fetchData() {
        // Strong reference cycle이 발생하는 부분
        completionHandler = { [weak self] in
            // self를 강하게 참조하여 메모리가 해제되지 않습니다.
            self?.processData()
        }
    }

    func processData() {
        print("데이터 처리 완료")
    }
}

위 코드 예시에서 self를 강하게 참조하여 'Strong reference cycle'이 형성됩니다. 이를 수정하기 위해 [weak self]를 사용하여 약한 참조(weak reference)를 해야 합니다.

메모리 경고 처리

iOS 애플리케이션은 메모리가 부족할 때 메모리 경고를 받을 수 있습니다. 이때 메모리 사용을 줄이기 위해 불필요한 메모리를 해제하는 것이 중요합니다.

swift
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // 여기에서 캐시 또는 불필요한 데이터를 해제하여 메모리 사용을 최적화합니다.
    imageCache.removeAllObjects()
}

결론

이 글에서는 iOS 메모리 관리의 기초 개념과 Compressed, Swapped, Resident 메모리에 대해 알아보았습니다. Swift로 구현한 예제를 통해 메모리 관리의 중요성을 이해하고, 메모리 사용 최적화를 위한 다양한 기법을 배웠습니다. 효과적인 메모리 관리로 보다 빠르고 안정적인 iOS 애플리케이션을 개발할 수 있기를 바랍니다.