Я начал использовать ARC недавно, и с тех пор я обвиняю его в каждой проблеме с памятью.:) Возможно, вы могли бы помочь мне лучше понять, что я делаю неправильно.
Мой текущий проект о CoreGraphics - графический чертеж, просмотры, заполненные эскизами и так далее. Я считаю, что при использовании ручного управления памятью не возникнет проблем, за исключением, может быть, нескольких зомби... Но на данный момент приложение просто падает каждый раз, когда я пытаюсь либо создать много миниатюр, либо перерисовать немного более сложный график.
Во время профилирования с помощью инструментов я вижу очень высокое значение в резидентной памяти, а также в грязной. Анализ кучи показывает довольно тревожный нерегулярный рост...
При рисовании всего нескольких эскизов резидентная память растет примерно на 200 МБ. Когда все нарисовано, память падает на почти то же значение, что и до рисования. Однако, с большим количеством эскизов, значение в резидентной памяти выше 400 МБ, и это явно приводит к сбою приложения. Я попытался ограничить количество эскизов, нарисованных в одно и то же время (NSOperationQueue и его maxConcurrentOperationCount), но поскольку освобождение так много памяти, кажется, занимает немного больше времени, это действительно не решило проблему.
Сейчас мое приложение в основном не работает, так как реальные данные работают со множеством сложных диаграмм - много эскизов.
Каждый эскиз создается с помощью этого кода, который я получил отсюда: (категория в UIImage)
+ (void)beginImageContextWithSize:(CGSize)size
{
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
if ([[UIScreen mainScreen] scale] == 2.0) {
UIGraphicsBeginImageContextWithOptions(size, YES, 2.0);
} else {
UIGraphicsBeginImageContext(size);
}
} else {
UIGraphicsBeginImageContext(size);
}
}
+ (void)endImageContext
{
UIGraphicsEndImageContext();
}
+ (UIImage*)imageFromView:(UIView*)view
{
[self beginImageContextWithSize:[view bounds].size];
BOOL hidden = [view isHidden];
[view setHidden:NO];
[[view layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
[self endImageContext];
[view setHidden:hidden];
return image;
}
+ (UIImage*)imageFromView:(UIView*)view scaledToSize:(CGSize)newSize
{
UIImage *image = [self imageFromView:view];
if ([view bounds].size.width != newSize.width ||
[view bounds].size.height != newSize.height) {
image = [self imageWithImage:image scaledToSize:newSize];
}
return image;
}
+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{
[self beginImageContextWithSize:newSize];
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
[self endImageContext];
return newImage;
}
Есть ли какой-нибудь другой способ, который бы не питал столько памяти или что-то действительно не так с кодом при использовании ARC?
В другом месте, где происходит предупреждение о сбое + аварии, происходит слишком много перерисовки любого вида. Это не нужно быть быстрым, просто много раз. Память складывается до тех пор, пока она не сработает, и я не смогу найти что-то действительно ответственное за нее. (Я вижу растущую резидентную/грязную память в VM Tracker и рост кучи в инструменте Allocations)
Мой вопрос в основном заключается в следующем: как найти, почему это происходит? Мое понимание заключается в том, что для данного объекта нет владельца, который был выпущен как можно скорее. Моя проверка кода предполагает, что многие объекты вообще не выпущены, хотя я не вижу причин для этого. Я не знаю о каких-либо циклах сохранения...
Я прочитал "Переход к заметкам о выпуске ARC", статью "bbum", посвященную анализу кучи и, вероятно, десятку других. Отличается каким-то анализом кучи с ARC и без нее? Я не могу ничего сделать с помощью .
Спасибо за любые идеи.
ОБНОВЛЕНИЕ: (чтобы не заставить всех читать все комментарии и выполнять мои обещания)
Добиваясь моего кода и добавляя @autoreleasepool, где он имел какой-то смысл, потребление памяти снижалось. Самая большая проблема заключалась в вызове UIGraphicsBeginImageContext
из фонового потока. После исправления (см. Ответ @Tammo Freese для получения подробной информации) освобождение произошло достаточно скоро, чтобы не сбой приложения.
Моя вторая авария (вызванная многими перерисовками одного и того же графика) была полностью решена путем добавления CGContextFlush(context)
в конце моего метода рисования. Позор мне.
Небольшое предупреждение для любого, кто пытается сделать что-то подобное: использовать OpenGL. CoreGraphics недостаточно быстро для анимации больших рисунков, особенно на iPad 3. (сначала с сетчаткой)