Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSCache doesn't delete items when under memory pressure when I am testing it, however the documentation says it does

Tags:

caching

ios

swift

This is what I see in the documentation.

The NSCache class incorporates various auto-eviction policies, which ensure that a cache doesn’t use too much of the system’s memory. If memory is needed by other applications, these policies remove some items from the cache, minimizing its memory footprint.

But when I look into the source code: https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSCache.swift

I see nothing about it somehow deletes items, when under memory pressure. It only deletes items when you reach the cost limit.

I made a small test:

class Data {
    var data = [Int]()

    init() {
        for i in 0..<1000000 {
            data.append(i)
        }
    }
}

var cache = NSCache<NSNumber, Data>()

for i in 0..<10000000 {
    cache.setObject(Data(), forKey: NSNumber(value: i))
}

And after that test the app eats all the memory and crashes. So. Does the documentation lie?

like image 991
Semyon Avatar asked Aug 28 '19 09:08

Semyon


People also ask

Is NSCache persistent?

NSCache is really nice for a few reasons: It stores data in memory only. If our app gets killed, this memory is freed up and it's not persisted to disk. The key-value pair mechanism lets us very easily set and get cached content.

How does NSCache work?

The NSCache class incorporates various auto-eviction policies, which ensure that a cache doesn't use too much of the system's memory. If memory is needed by other applications, these policies remove some items from the cache, minimizing its memory footprint.

What is an efficient way to cache data in memory Swift?

Avoiding stale data What makes NSCache a better fit for caching values compared to the collections found in the Swift standard library (such as Dictionary ) is that it'll automatically evict objects when the system is running low on memory — which in turn enables our app itself to remain in memory for longer.

Is NSCache thread safe?

One more thing about NSCache is, it is thread safe. We can access it from any thread without worrying about managing threads while accessing NSCache. You can set & get name for cache. The default value is an empty string (“”).


1 Answers

First, and most importantly, swift-corelibs-foundation is not the Foundation from iOS and macOS:

This project, swift-corelibs-foundation, provides an implementation of the Foundation API for platforms where there is no Objective-C runtime. On macOS, iOS, and other Apple platforms, apps should use the Foundation that comes with the operating system. Our goal is for the API in this project to match the OS-provided Foundation and abstract away the exact underlying platform as much as possible.

Next, your test case does not carefully test NSCache. Your Data objects could be stored on the autorelease pool and not released. In this case that's not true, but it's the kind of thing you need to be very careful about when testing memory usage.

That said, I can't reproduce your issue. When I put this in an iOS app and run it on iOS 12, I see the kind of behavior you're probably expecting:

enter image description here

Big run-up in memory usage to ~1GB, at which point the cache is dumped as expected.

I also wasn't able to easily reproduce it on macOS (but I wasn't patient enough to let it crash, so it's possible it eventually would). You'll need to give a more precise example of where this crashes unexpectedly in order to diagnose why.

like image 118
Rob Napier Avatar answered Sep 28 '22 10:09

Rob Napier