NSCache не выдает данные

NSCache - редко используемый инструмент, который на самом деле выглядит весьма полезным. Я создал простой эксперимент, чтобы увидеть, как он работает, и похоже, что он не автоматически выдает данные в ситуациях с низкой памятью (или я делаю что-то неправильно!)

- (void)viewDidLoad
{
    _testCache = [[NSCache alloc] init];

    // Allocate 600 MB of zeros and save to NSCache
    NSMutableData* largeData = [[NSMutableData alloc] init];
    [largeData setLength:1024 * 1024 * 600]; 
    [_testCache setObject:largeData forKey:@"original_Data"];
}

- (IBAction)buttonWasTapped:(id)sender {

    // Allocate & save to cache 300 MB each time the button is pressed
    NSMutableData* largeData = [[NSMutableData alloc] init];
    [largeData setLength:1024 * 1024 * 300]; 
    static int count = 2;
    NSString* key = [NSString stringWithFormat:@"test_data_%d", count++];
    [_testCache setObject:largeData forKey:key];

    NSMutableData* dataRecoveredFromCache = [_testCache objectForKey:@"original_Data"];

    if (dataRecoveredFromCache) {
        NSLog(@"Original data is ok");
    } else {
        NSLog(@"Original data is missing (purged from cache)");
    }
}

Итак, я запустил приложение в симуляторе и несколько раз нажал кнопку, но ни один элемент не был выселен... Приложение в итоге разбилось:

2012-07-17 14:19:36.877 NSCacheTest[15302:f803] Data is ok
2012-07-17 14:19:37.365 NSCacheTest[15302:f803] Data is ok
2012-07-17 14:19:37.861 NSCacheTest[15302:f803] Data is ok
2012-07-17 14:19:38.341 NSCacheTest[15302:f803] Data is ok
2012-07-17 14:19:38.821 NSCacheTest[15302:f803] Data is ok
NSCacheTest(15302,0xac0942c0) malloc: *** mmap(size=393216000) failed (error code=12)
*** error: can't allocate region

Ответ 1

Из документа doc (Emphasis mine): класс NSCache включает различные политики автоматического удаления, которые гарантируют, что он не использует слишком большую часть системной памяти. Система автоматически выполняет эти политики, если требуется память других приложений. При вызове эти политики удаляют некоторые элементы из кеша, сводя к минимуму объем памяти.

Apple не заявляет, что память будет освобождена при предупреждении памяти. По моему опыту, кеш чаще всего очищается, когда приложение переходит в фоновый режим или когда вы добавляете более крупные элементы.

Ответ 2

Здесь цитируются документы...

Класс NSCache включает различные политики автоматического удаления, которые убедитесь, что он не использует слишком большую часть системной памяти. система автоматически выполняет эти политики, если требуется других приложений. При вызове эти политики удаляют элементы некоторыеиз кеша, минимизируя его объем памяти.

... как вы можете видеть, он указывает, что он удаляет элементы some, а не все элементы. Это зависит от внутренних политик NSCache, доступной памяти, состояния устройства и т.д. Вы не должны беспокоиться об этих политиках.

Вы можете управлять ими с помощью свойств countLimit, totalCostLimit, и вы можете добавить объект со стоимостью, посмотрите setObject:forKey:cost:.

Также вы можете самостоятельно вырезать объекты. Добавьте к вашим объектам реализацию протокола NSDiscardableContent и setEvictsObjectsWithDiscardedContent: до YES.

Ответ 3

Я тоже использую этот класс. Обратите внимание, что в документации указано, что NSCache привязан к ОС и, вероятно, имеет доступ к информации о памяти в глубине ОС. Предупреждение о памяти - это просто сообщение об ошибке памяти для appDelegate/viewControllers.

Если вы действительно хотите протестировать свой код, вам, вероятно, понадобится тестовый режим, в котором вы начнете массировать много памяти (создавая огромную утечку, если можно так выразиться). Возможно, вам понадобится пакет в кусках во время каждой основной runloop, поэтому ОС имеет возможность увидеть, как он падает вниз (у меня есть приложение, которое пережевывает много памяти, и это так быстро происходит на 3GS, что его просто убивают никогда не получая предупреждения о памяти.