iOS 메모리 최적화

호씨·2024년 12월 23일
0

[iOS] 메모리 최적화 🚀

목차

  1. 메모리 관리의 기본 개념
  2. 메모리 사용량 모니터링
  3. 이미지 처리 최적화
  4. 메모리 누수 방지
  5. 백그라운드 상태 메모리 관리
  6. 객체 수명 주기 관리

1. 메모리 관리의 기본 개념

1.1 iOS의 메모리 유형

iOS는 가상 메모리 시스템을 통해 각 앱에 독립된 메모리 공간을 제공한다. 메모리는 크게 세 가지 유형으로 나눌 수 있다.

Clean Memory (정리 가능한 메모리)

  • 시스템이 필요할 때 해제할 수 있는 메모리
  • 앱 실행에 직접적인 영향을 주지 않는 데이터
  • 예: 캐시 데이터, 재생성 가능한 리소스

Dirty Memory (정리 불가능한 메모리)

  • 재생성할 수 없는 중요 데이터 저장
  • 앱 실행에 필수적인 데이터
  • 과도한 사용 시 앱 종료 위험

Compressed Memory (압축 메모리)

  • 사용하지 않는 데이터를 압축하여 저장
  • 메모리 사용량 감소 효과
  • 압축 해제 시 약간의 성능 저하 가능

1.2 ARC (Automatic Reference Counting)

iOS의 메모리 관리는 ARC를 기반으로 합니다.

주요 특징:

  • 객체의 참조 카운트를 자동으로 관리
  • 참조가 없어지면 메모리 자동 해제
  • 개발자의 직접적인 메모리 관리 필요성 감소

ARC의 한계:

  • 순환 참조 문제 해결 불가
  • 강한 참조 관계 수동 관리 필요
  • 특정 상황에서 메모리 누수 발생 가능

2. 메모리 사용량 모니터링

2.1 Xcode 도구 활용

Xcode는 다양한 메모리 분석 도구를 제공합니다:

Instruments - Allocations

  • 객체 생성과 메모리 할당 추적
  • 메모리 누수 감지
  • 불필요한 객체 생성 파악

Instruments - Leaks

  • 실시간 메모리 누수 감지
  • 누수 발생 지점 식별
  • 참조 관계 시각화

Instruments - VM Tracker

  • 가상 메모리 사용 패턴 분석
  • 메모리 관리 문제 파악
  • 시스템 리소스 사용량 모니터링

Memory Debugger

  • 런타임 메모리 상태 확인
  • 객체 참조 관계 그래프
  • 메모리 문제 시각적 분석

2.2 메모리 경고 대응

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    
    // 캐시 데이터 제거
    imageCache.removeAllObjects()
    
    // 불필요한 리소스 해제
    temporaryData = nil
    
    // 재생성 가능한 데이터 정리
    recreatableResources.removeAll()
}

3. 이미지 처리 최적화

3.1 이미지 로드 최적화 전략

Image I/O Framework 활용

func loadOptimizedImage(from url: URL) -> UIImage? {
    let options: [CFString: Any] = [
        kCGImageSourceShouldCache: false,
        kCGImageSourceShouldCacheImmediately: false
    ]
    
    guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, options as CFDictionary) else {
        return nil
    }
    
    // 이미지 속성 확인
    guard let image = CGImageSourceCreateImageAtIndex(imageSource, 0, options as CFDictionary) else {
        return nil
    }
    
    return UIImage(cgImage: image)
}

3.2 이미지 다운샘플링

고해상도 이미지의 메모리 사용량을 줄이는 핵심 기술입니다.

func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage? {
    // 기본 옵션 설정
    let options = [kCGImageSourceShouldCache: false] as CFDictionary
    
    guard let source = CGImageSourceCreateWithURL(imageURL as CFURL, options) else {
        return nil
    }
    
    // 최대 차원 계산
    let maxDimension = max(pointSize.width, pointSize.height) * scale
    
    // 다운샘플링 옵션 설정
    let downsampleOptions = [
        kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceShouldCacheImmediately: true,
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceThumbnailMaxPixelSize: maxDimension
    ] as CFDictionary
    
    guard let image = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions) else {
        return nil
    }
    
    return UIImage(cgImage: image)
}

3.3 효율적인 이미지 캐싱

class ImageCache {
    static let shared = ImageCache()
    private let cache = NSCache<NSString, UIImage>()
    
    func setImage(_ image: UIImage, forKey key: String) {
        cache.setObject(image, forKey: key as NSString)
    }
    
    func image(forKey key: String) -> UIImage? {
        return cache.object(forKey: key as NSString)
    }
    
    func removeImage(forKey key: String) {
        cache.removeObject(forKey: key as NSString)
    }
    
    func clearCache() {
        cache.removeAllObjects()
    }
}

4. 메모리 누수 방지

4.1 순환 참조 해결

클로저에서 순환 참조를 방지하는 방법:

class DataManager {
    var completionHandler: (() -> Void)?
    
    func fetchData() {
        // [weak self] 사용으로 순환 참조 방지
        completionHandler = { [weak self] in
            self?.processData()
        }
    }
    
    private func processData() {
        // 데이터 처리 로직
    }
}

4.2 Weak vs Unowned 참조

// Weak 참조 예시
class Parent {
    weak var child: Child?
}

// Unowned 참조 예시
class Customer {
    unowned let creditCard: CreditCard
    init(creditCard: CreditCard) {
        self.creditCard = creditCard
    }
}

5. 백그라운드 상태 메모리 관리

class AppDelegate: UIResponder, UIApplicationDelegate {
    func applicationDidEnterBackground(_ application: UIApplication) {
        // 이미지 캐시 정리
        ImageCache.shared.clearCache()
        
        // 임시 데이터 정리
        TemporaryStorage.shared.clearAll()
        
        // 메모리 집중적인 리소스 해제
        ResourceManager.shared.releaseMemoryIntensiveResources()
    }
}

6. 객체 수명 주기 관리

6.1 뷰 컨트롤러 메모리 관리

class ExampleViewController: UIViewController {
    private var timer: Timer?
    private var dataTask: URLSessionDataTask?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTimer()
        fetchData()
    }
    
    private func setupTimer() {
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            self?.updateUI()
        }
    }
    
    private func fetchData() {
        dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
            self?.handleResponse(data, response, error)
        }
        dataTask?.resume()
    }
    
    deinit {
        timer?.invalidate()
        dataTask?.cancel()
        print("ExampleViewController deallocated")
    }
}

마무리

iOS 앱 개발에서 메모리 최적화는 앱의 성능과 안정성에 직접적인 영향을 미치는 중요한 요소다.
이 글에서 다룬 내용들을 실제 프로젝트에 적용하면서, 지속적인 모니터링과 최적화를 통해 더 나은 앱을 만들어야겠다.

참고자료

  • Apple Developer Documentation
  • WWDC 세션
  • iOS 개발 관련 기술 블로그
profile
이것저것 많이 해보고싶은 사람

0개의 댓글

관련 채용 정보