Предупреждение памяти и сбой (ARC)-как определить, почему это происходит?

Я начал использовать 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)

Мой вопрос в основном :как найти, почему это вообще происходит? Насколько я понимаю, когда у данного объекта нет владельца, он освобождается как можно скорее. Моя проверка кода показывает, что многие объекты вообще не освобождаются, хотя я не вижу причин для этого. Я не знаю ни о каких циклах сохранения...

Я прочитал примечания к выпуску Transitioning to ARC, статью bbum об анализе кучи и, вероятно, дюжину других. Чем отличается анализ кучи с ARC и без? Кажется, я не могу сделать ничего полезного с его выводом .

Спасибо за любые идеи.

ОБНОВЛЕНИЕ:(чтобы не заставлять всех читать все комментарии и сдержать обещание)

Благодаря тщательному просмотру моего кода и добавлению @autoreleasepool там, где это имело смысл, потребление памяти снизилось. Самой большой проблемой был вызов UIGraphicsBeginImageContextиз фонового потока. После исправления (подробности см. в ответе @Tammo Freese )отключение произошло достаточно быстро, чтобы не вызвать сбой приложения.

Мой второй сбой (, вызванный многочисленными перерисовками одной и той же диаграммы ), был полностью решен добавлением CGContextFlush(context)в конце моего метода рисования. Мне стыдно.


Небольшое предупреждение для тех, кто пытается сделать что-то подобное:используйте OpenGL. CoreGraphics недостаточно быстр для анимации больших рисунков, особенно на iPad 3.(первый с сетчаткой)

15
задан xius 14 January 2013 в 21:17
поделиться