Project/개발 업무

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

lgvv 2026. 3. 25. 23:02

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

 

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

 

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

 

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

 

왜 동적 설정이 필요할까?

 

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

 

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

 

고사양 기기의 경우

 

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

 

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

 

전체 코드

 

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

 

  • 아래 코드에서 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")
}

 

iPhone 14 Pro (모델 식별자 iPhone15,2, physicalMemory 약 5GB)

 

이미지 01 - iPhone 14 Pro (iPhone15,2)
이미지 01 - iPhone 14 Pro (iPhone15,2)

 

iPhone 12 mini (모델 식별자 iPhone13,1, physicalMemory 약 3GB)

 

이미지 02 - iPhone 12 mini (iPhone13,1)
이미지 02 - iPhone 12 mini (iPhone13,1)

 

모델 식별자는 마케팅 이름과 다름. iPhone15,2는 iPhone 14 Pro, iPhone13,1은 iPhone 12 mini임.

 

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

 

(참고) Android 비트맵 캐싱