Недостаточно памяти при создании UIImage в закадровом растровом контексте с помощью NSOperation - PullRequest
0 голосов
/ 19 апреля 2010

У меня есть приложение с несколькими подклассами UIView, которое действует как страницы для UIScrollView. UIViews перемещаются вперед и назад, чтобы обеспечить беспроблемное взаимодействие с пользователем. Поскольку содержимое представлений довольно медленно отрисовывается, оно отображается на одном общем CGBitmapContext, защищенном блокировками подклассами NSOperation - выполняемыми по одному в NSOperationQueue - заключенными в UIImage и затем используемыми основным потоком для обновления содержимого просмотров.

-(void)main {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];

if([self isCancelled]) {
    return;
}
if(nil == data) {
    return; 
}

// Buffer is the shared instance of a CG Bitmap Context wrapper class
// data is a dictionary
CGImageRef img = [buffer imageCreateWithData:data];
UIImage * image = [[UIImage alloc]initWithCGImage:img];
CGImageRelease(img);

if([self isCancelled]) {
    [image release];
    return;
}

NSDictionary * result = [[NSDictionary alloc]initWithObjectsAndKeys:image,@"image",id,@"id",nil];

// target is the instance of the UIView subclass that will use
// the image
[target performSelectorOnMainThread:@selector(updateContentWithData:) withObject:result waitUntilDone:NO];

[result release];
[image release];

[pool release];
}

updateContentWithData: подкласса UIView, выполняемого в основном потоке, так же просто

-(void)updateContentWithData:(NSDictionary *)someData {

NSDictionary * data = [someData retain];

if([[data valueForKey:@"id"]isEqualToString:[self pendingRequestId]]) {

    UIImage * image = [data valueForKey:@"image"];
    [self setCurrentImage:image];
    [self setNeedsDisplay];

}

// If the image has not been retained, it should be released together
// with the dictionary retaining it
[data release];
}

DrawLayer: inContext: метод подкласса просто получит CGImage из UIImage и использует его для обновления вспомогательного слоя или его части. В процессе не участвует сохранение или освобождение.

Проблема в том, что через некоторое время у меня заканчивается память. Количество UIViews является статическим. CGImageRef и UIImage создаются, сохраняются и освобождаются правильно (или мне так кажется). В приборах нет никаких утечек, просто свободная память постоянно падает, увеличивается в несколько раз, а затем падает еще ниже, пока приложение не будет закрыто. До этого приложение перебирает около 2-300 из вышеупомянутых страниц, но я ожидаю, что использование памяти достигнет более или менее стабильного уровня используемой памяти после того, как несколько страниц уже были просмотрены на высокой скорости или, так как изображения размером до 3 МБ, более раннее, чем раньше.

Любое предложение будет с благодарностью.

1 Ответ

0 голосов
/ 04 февраля 2011

Я понимаю, что это старая публикация, но на случай, если она кому-нибудь поможет ... Это похоже на случай фрагментации памяти. У нас есть приложение, которое ведет себя так же. Объем памяти, фактически выделенный приложением, никогда не достигает опасных уровней, но если вы посмотрите на объем резидентной памяти для приложения (используя моментальные снимки VM Tracker в инструменте Allocations или в инструменте Activity Monitor), он неумолимо поднимается со временем, пока не очень большой переходный всплеск убивает приложение.

Данное приложение представляет собой многопоточное приложение, которое создает тонны переходных распределений в широком диапазоне размеров, время которых невозможно предсказать или контролировать. Такое приложение должно быть параноидально в отношении освобождения ненужных выделений памяти не потому, что оно само по себе занимает слишком много памяти, а потому, что оно может создавать дыры, которые не позволяют большим изображениям помещаться в выделенные блоки. Даже меньшие выделения, которые, как правило, упускаются из виду, важны для фрагментации (при условии, что распределитель низкого уровня выполняет групповые распределения по размеру, что полезно в некоторой степени). Зоны памяти теоретически полезны для решения проблемы фрагментации, но сделать их достаточно сложно, по крайней мере, по моему опыту. Кроме того, используйте пользовательские пулы автоматического выпуска, или, что еще лучше, выделите / инициализируйте как можно больше и выпустите как можно раньше. Тот факт, что базовые структуры всегда выделяют свои ресурсы для кэширования, вероятно, не помогает.

...