project/개발 업무

기기별 RAM 용량에 따른 이미지 동적 캐시 사이즈 설계

lgvv 2026. 3. 25. 23:02

기기별 RAM 용량에 따른 이미지 동적 캐시 사이즈 설계

 
글로벌 서비스를 운영하다 보면, 여전히 RAM 2GB~3GB 수준의 구형 기기 사용자를 무시할 수 없음.
iPhone 8, iPhone SE 1세대, 일부 보급형 기기처럼 메모리 여유가 크지 않은 환경에서는, 캐시 전략 하나만으로도 앱 안정성이 크게 달라질 수 있음.
 
이미지 캐시는 사용자 경험을 빠르게 만들기 위한 중요한 장치지만, 동시에 메모리를 많이 사용하는 기능이기도 함.
그래서 캐시 크기를 고정값으로 두면 다음과 같은 문제가 생김

  • 저사양 기기에서는 메모리 압박으로 크래시 위험이 커짐
  • 고사양 기기에서는 더 많은 자원을 활용하지 못해 비효율이 발생함

기기의 물리적 RAM 용량을 기준으로 이미지 캐시 사이즈를 동적으로 결정하는 방식을 적용

 

왜 동적 설정이 필요할까?

iOS는 앱이 사용할 수 있는 메모리 한도를 초과하면 명시적인 에러 없이 프로세스를 종료할 수 있음.

저사양 기기의 경우

  • RAM 2GB 기기에서 캐시를 1GB로 고정하는 것은 실제 사용 가능한 메모리 대비 과도한 점유가 될 수 있음.
  • 경우에 따라서는 결과적으로 메모리 부족으로 인한 크래시 확률이 높아짐.

고사양 기기의 경우

  • 이미지 디스크 접근 증가
  • 네트워크 재요청 증가
  • 이미지 디코딩 비용 증가
  • 스크롤 체감 성능 저하

즉, 캐시를 너무 작게 잡아도 손해가 커서 기기별 메모리 특성에 맞게끔 균형을 찾고자 함.


전체 코드

메모리 캐시 사이즈에 기기별 가용 가능한 메모리 크기를 기반으로 상한값을 다르게 설정.
pyshicalMemory는 기기 스펙의 메모리 용량과 일치하지 않음.

  • 아래 코드에서 1/8 값을 사용하고 있으나 프로젝트 특성에 맞게 변경해도 됨.
    • 안드로이드 공식 문서에서 1/8 사용하고 있는 예제가 있어서 그대로 적용
private func configureImageCacheLimits() {
        // 기기의 물리적 RAM 전체 용량 (단위: bytes)
        // 예) 6GB RAM → 6,442,450,944 bytes
        let physicalMemory = ProcessInfo.processInfo.physicalMemory
        // 이미지 캐시에 허용할 최소 메모리 한도 (단위: MB)
        let minimumLimitMB: UInt64 = 100
        
        // 이미지 캐시에 허용할 최대 메모리 한도 (단위: MB)
        let maximumLimitMB: UInt64 = 512
        
        // physicalMemory(bytes) → MB 변환 과정:
        //   ÷ 8          : 전체 RAM의 1/8만 캐시에 사용 (나머지는 OS or 앱 등이 사용)
        //   ÷ 1024       : bytes → KB
        //   ÷ 1024       : KB → MB
        //
        // 예) 6GB RAM 기기:
        //   6,442,450,944 ÷ 8 = 805,306,368 bytes (약 768MB, RAM의 1/8)
        //   805,306,368 ÷ 1024 = 786,432 KB레
        //   786,432 ÷ 1024 = 768 MB
        //   → min(512, 768) = 512 → max(100, 512) = 512MB 적용
        //
        // 예) 2GB RAM 기기:
        //   2,147,483,648 ÷ 8 = 268,435,456 bytes (약 256MB)
        //   → 256MB → max(100, 256) = 256MB 적용
        let computedLimitMB = max(
            minimumLimitMB,
            min(maximumLimitMB, physicalMemory / 8 / 1024 / 1024)
        )
        
        // 최종 캐시 한도를 다시 bytes로 변환 (SDImageCache에 bytes 단위로 전달해야 하므로)
        // 예) 512MB → 512 × 1024 × 1024 = 536,870,912 bytes
        let physicalMemoryMB = physicalMemory / 1024 / 1024
        let physicalMemoryGB = physicalMemoryMB / 1024
        
        var systemInfo = utsname()
        uname(&systemInfo)
        let deviceModel = withUnsafePointer(to: &systemInfo.machine) {
            $0.withMemoryRebound(to: CChar.self, capacity: 1) {
                String(validatingUTF8: $0) ?? "Unknown"
            }
        }
        
        print("기기 모델: \(deviceModel)")
        print("물리 메모리: \(physicalMemoryGB) GB")
        print("캐시 한도: \(computedLimitMB) MB")
    }

 
 
아이폰 15 Pro

아이폰 15 Pro

 
아이폰 13 mini

아이폰 13 미니

 

기기 RAM 1/8 계산값 최종 적용
iPhone SE (1st) 2GB 256MB 256MB
iPhone 11 4GB 512MB 512MB
iPhone 15 Pro 6GB 1024MB 512MB (상한 제한)

 
 
 
 
(참고)
https://developer.android.com/topic/performance/graphics/cache-bitmap?hl=ko

 

비트맵 캐싱  |  App quality  |  Android Developers

단일 비트맵을 사용자 인터페이스(UI)에 로드하는 것은 간단하지만 한 번에 더 큰 이미지의 집합을 로드해야 하면 더 복잡해집니다. 많은 경우(ListView, GridView 또는 LruCache 클래스와 같은 구성요소

developer.android.com