Проблемы с памятью с UIImagePicker - PullRequest
2 голосов
/ 27 мая 2010

Я создаю приложение, в котором есть несколько разных разделов, и все они довольно объемные. Это связано с веб-сайтом моего клиента, и они представляют собой одежду «высокого дизайна».

Одна часть приложения - это изображения, загруженные с камеры или библиотеки, и табличное представление, которое показывает сетку миниатюр. Достаточно надежно, когда я имею дело с версией UIImagePickerControl для камеры, я получаю удар по нехватке памяти. Если я какое-то время прыгаю вокруг этой части приложения, я время от времени и неповторимо вырываюсь с «status: 10 (SIGBUS)» в отладчике.

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

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Low Memory Warning"
                                                    message:@"Cleaning out events data"
                                                   delegate:nil
                                          cancelButtonTitle:@"All right then."
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];

    NSInteger spaceSaved;

    DataManager *data = [DataManager sharedDataManager];
    for (Event *event in data.eventList) {
        spaceSaved += [(NSData *)UIImagePNGRepresentation(event.image) length];
        event.image = nil;
        spaceSaved -= [(NSData *)UIImagePNGRepresentation(event.image) length];
    }

    NSString *titleString = [NSString stringWithFormat:@"Saved %d on event images", spaceSaved];

    for (WondrMark *mark in data.wondrMarks) {
        spaceSaved += [(NSData *)UIImagePNGRepresentation(mark.image) length];
        mark.image = nil;
        spaceSaved -= [(NSData *)UIImagePNGRepresentation(mark.image) length];
    }

    NSString *messageString = [NSString stringWithFormat:@"And total %d on event and mark images", spaceSaved];

    NSLog(@"%@ - %@", titleString, messageString);

    // Relinquish ownership any cached data, images, etc that aren't in use.
}

Как вы можете видеть, я делаю (плохую) попытку взглянуть на пространство памяти, которое я освобождаю. Я знаю, что это не говорит мне о фактической памяти самих UIImages, но, по крайней мере, дает мне НЕКОТОРЫЕ числа, так что я вижу, что ЧТО-ТО происходит. (Извините за неудобный способ, которым я создаю это сообщение NSLog - я собирался запустить другой UIAlertView, но понял, что было бы более полезно зарегистрировать его.)

Довольно надежно, после того, как я на некоторое время переключаюсь в части изображения приложения, я открою интерфейс камеры и получу UIAlertView с малым объемом памяти, как три или четыре раза подряд. Вот вывод NSLog за последний раз, когда я его видел:

2010-05-27 08:55:02.659 EverWondr[7974:207] Saved 109591 on event images - And total 1419756 on event and mark images
wait_fences: failed to receive reply: 10004003
2010-05-27 08:55:08.759 EverWondr[7974:207] Saved 4 on event images - And total 392695 on event and mark images
2010-05-27 08:55:14.865 EverWondr[7974:207] Saved 4 on event images - And total 873419 on event and mark images
2010-05-27 08:55:14.969 EverWondr[7974:207] Saved 4 on event images - And total 4 on event and mark images
2010-05-27 08:55:15.064 EverWondr[7974:207] Saved 4 on event images - And total 4 on event and mark images

И вскоре после этого мы получаем выход SIGBUS. Такова ситуация. Теперь мои конкретные вопросы:

Время, когда я вижу это, происходит, когда диафрагма камеры UIPickerView выключается. Я нажимаю кнопку, чтобы сделать снимок, он выполняет анимацию «щелчка», и Instruments показывает мой объем памяти, занимающий от 10 МБ до 25 МБ, и остается там до тех пор, пока изображение не будет доставлено в мой UIViewController, где использование снизится до 10 или 11мб снова. Если мы сделаем это без предупреждения памяти, мы золотые, но, скорее всего, мы не будем. Что я могу сделать, чтобы это не было так дорого?

Во-вторых, у меня включены NSZombies. Правильно ли я понимаю, что это на самом деле препятствует освобождению памяти? Я подвергаю свое приложение нечестной тестовой среде?

В-третьих, есть ли какой-нибудь способ программно получить использование моей памяти? Или хотя бы использование объекта UIImage? Я просмотрел документы и ничего об этом не вижу.

1 Ответ

4 голосов
/ 27 мая 2010

Эти функции дают вам представление об общем использовании памяти и общей свободной памяти. У меня в приложении есть таймер на 1 секунду, каждую секунду в нем заносится журнал и освобождается место на диске (если оно изменилось> 0,5 Мб), это помогает мне лучше видеть происходящее:

#import "mach/mach.h"

vm_size_t usedMemory(void) {
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
    return (kerr == KERN_SUCCESS) ? info.resident_size : 0;   // size in bytes
}

natural_t freeMemory(void) {
    mach_port_t           host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t              pagesize;
    vm_statistics_data_t   vm_stat;

    host_page_size(host_port, &pagesize);
    (void) host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size); 
    return vm_stat.free_count * pagesize;
}

EDIT1 - функция class_getInstanceSize дает вам размер экземпляра объекта, но я никогда не пробовал его, и, вероятно, он не разыменовывает ivar и не сводит их использование. Но, может быть, это поможет вам.

EDIT2 Эта функция дает вам размер UIImage:

size_t sizeofUIImage(UIImage* image) {
    return CGImageGetBytesPerRow(image.CGImage) * CGImageGetHeight(image.CGImage);
}

EDIT4 Вот фрагмент кода из моего метода обработки 1-секундного таймера, который помогает увидеть, как работает ваше приложение, прежде чем возникнут проблемы с памятью. Конечно, свободная память зависит от того, какие фоновые задачи выполняются (Safari, Mail и т. Д.), Которые вы не можете контролировать:

void logMemUsage(void) {
    // compute memory usage and log if different by >= 100k
    static long prevMemUsage = 0;
    long curMemUsage = usedMemory();
    long memUsageDiff = curMemUsage - prevMemUsage;

    if (memUsageDiff > 100000 || memUsageDiff < -100000) {
        prevMemUsage = curMemUsage;
        NSLog(@"Memory used %7.1f (%+5.0f), free %7.1f kb", 
            curMemUsage/1000.0f, memUsageDiff/1000.0f, freeMemory()/1000.0f);
    }
}

Кредиты: свободные / используемые функции памяти, полученные из здесь и здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...