CS, Swift: LFU(Least Frequently Used) 기법 이용해서 ImageCacher 구현해보기

Insub
4 min readJul 7, 2024

--

들어가며

최근에 정보처리기사를 공부하며 LRU(Least Recently Used), LFU(Least Frequently Used)에 대해 공부한 것을 실전에 적용하기 위해 이미지 캐셔를 구현해보겠습니다. 이 글에서는 LFU 캐싱 전략을 사용하여 간단하면서도 효율적인 ImageCacher를 만들어 보겠습니다.

이전 포스트

설명

LFU 캐싱은 가장 많이 사용된 데이터를 캐시에 유지하고, 사용 빈도가 낮은 데이터를 제거하는 방식입니다. 이를 통해 자주 사용되지 않는 데이터는 자동으로 제거하고, 자주 사용되는 데이터는 캐시에 남겨둘 수 있습니다. 아래의 코드는 Swift의 actor를 활용하여 스레드 안전한 LFU 캐시를 구현한 예제입니다.

import UIKit

actor ImageCacher {

static let shared = ImageCacher()
private init() { }

private var cachedImages: [String: UIImage] = [:]
private var accessFrequency: [String: Int] = [:]
private let cacheLimit = 100

func cachedImage(for key: String) -> UIImage? {
if let image = cachedImages[key] {
updateAccessFrequency(for: key)
return image
}
return nil
}

func cacheImage(_ image: UIImage, for key: String) {
if cachedImages.keys.count >= cacheLimit {
removeLeastFrequentlyUsedImage()
}
cachedImages[key] = image
updateAccessFrequency(for: key, initial: true)
}

private func updateAccessFrequency(for key: String, initial: Bool = false) {
if initial {
accessFrequency[key] = 1
} else {
accessFrequency[key, default: 0] += 1
}
}

private func removeLeastFrequentlyUsedImage() {
if let leastFrequentlyUsedKey = accessFrequency.min(by: { $0.value < $1.value })?.key {
cachedImages.removeValue(forKey: leastFrequentlyUsedKey)
accessFrequency.removeValue(forKey: leastFrequentlyUsedKey)
}
}
}

코드 설명

캐시 구조:

  • cachedImages: 이미지 데이터를 저장하는 딕셔너리입니다.
  • accessFrequency: 각 이미지 키의 접근 빈도를 저장하는 딕셔너리입니다.
  • cacheLimit: 캐시에 저장할 이미지의 최대 수를 설정합니다.

cachedImage(for:):

  • 주어진 키에 해당하는 이미지를 반환합니다.
  • 이미지가 존재하면 접근 빈도를 업데이트합니다.

cacheImage(_:for:):

  • 주어진 키와 이미지 데이터를 캐시에 저장합니다.
  • 캐시의 크기가 제한을 초과하면 가장 적게 사용된 이미지를 제거합니다.
  • 접근 빈도를 업데이트합니다.

updateAccessFrequency(for:initial:):

  • 접근한 키의 접근 빈도를 업데이트합니다.
  • 초기 저장 시 접근 빈도를 1로 설정합니다.

removeLeastFrequentlyUsedImage():

  • 접근 빈도가 가장 낮은 이미지를 찾아서 제거합니다.

결론

LFU(Least Frequently Used) 페이지 교체 기법을 활용한 이미지 캐셔를 구현했습니다. 이 방식은 자주 사용되지 않는 데이터를 자동으로 제거하여 메모리 사용을 효율적으로 관리할 수 있습니다. Swift의 actor를 사용하여 스레드 안전성을 보장하였습니다. LFU는 자주 사용되는 데이터를 캐시에 남기고, 사용 빈도가 낮은 데이터를 제거하는 방식으로, 캐시 히트율을 높이는 데 효과적입니다.

--

--