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
3 ответа
Из документа (выделено мной): класс NSCache включает в себя различные политики автоматического удаления, которые гарантируют, что он не использует слишком много системной памяти. Система автоматически выполняет эти политики, если память требуется другим приложениям. При вызове эти политики удаляют некоторые элементы из кэша, минимизируя объем занимаемой им памяти.
Apple не заявляет, что память будет освобождена по предупреждению памяти - по моему опыту, кэш чаще всего очищается, когда приложение переходит в фоновый режим или когда вы добавляете более крупные элементы.
Вот цитаты из документов...
Класс NSCache включает в себя различные политики автоматического удаления, которые гарантируют, что он не использует слишком много системной памяти. Система автоматически выполняет эти политики, если память требуется другим приложениям. При вызове эти политики удаляют некоторые элементы из кэша, минимизируя объем занимаемой им памяти.
... как вы можете видеть, он утверждает, что удаляет некоторые элементы, а не все элементы. Это зависит от NSCache
внутренние политики, доступная память, состояние устройства и т. д. Вам не следует беспокоиться об этих политиках.
Вы можете контролировать их с countLimit
, totalCostLimit
свойства, и вы можете добавить объект со стоимостью, посмотрите на setObject:forKey:cost:
,
Также вы можете выселять объекты самостоятельно. добавлять NSDiscardableContent
реализация протокола для ваших объектов и setEvictsObjectsWithDiscardedContent
: к YES
,
Я тоже использую этот класс. Обратите внимание, что в документации говорится, что NSCache связан с ОС и, вероятно, имеет доступ к информации о памяти глубоко внутри ОС. Предупреждение о памяти - просто отправляет предупреждение о памяти в appDelegate/viewControllers.
Если вы действительно хотите протестировать свой код, вам, вероятно, понадобится тестовый режим, в котором вы начнете неправильно использовать много памяти (создавая, так сказать, огромную утечку). Вам может понадобиться разбивать это на куски во время каждого основного цикла выполнения, поэтому у ОС есть возможность увидеть, как у него падает память (у меня есть приложение, которое жует много памяти, и оно делает это так быстро на 3GS, что его просто убивают) никогда не получая предупреждение памяти.