Основные данные iPhone - извлеченные управляемые объекты не освобождаются на устройстве (отлично на симуляторе) - PullRequest
3 голосов
/ 06 июня 2011

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

Я выполняю базовый executeFetchRequest на моем основном объекте данных, но массив возвращаемых управляемых объектов, кажется, никогда не освобождается ТОЛЬКО, когда яЗапустите его на iPhone, под симулятором он работает точно так же, как ожидалось.

Это несмотря на использование NSAutoreleasePool для обеспечения минимального использования памяти.Я также проверил с инструментами, и нет никаких утечек, только когда-либо увеличивая выделение памяти (с помощью '[NSManagedObject (_PFDynamicAccessorsAndPropertySupport) allocWithEntity:]').В моем реальном приложении это в конечном итоге приводит к вызову didReceiveMemoryWarning.

Я создал минимальную программу, которая воспроизводит описанную ниже проблему.Я пробовал разные вещи, такие как повреждение всех предметов перед тем, как осушить бассейн, но без радости.Если я предоставлю указатель NSError на выборку, ошибка не будет возвращена.Не работают фоновые потоки.

#import <mach/mach.h>
#import <mach/mach_host.h>

+(natural_t) get_free_memory {
    mach_port_t host_port;
    mach_msg_type_number_t host_size;
    vm_size_t pagesize;
    host_port = mach_host_self();
    host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    host_page_size(host_port, &pagesize);
    vm_statistics_data_t vm_stat;
    if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS) {
        NSLog(@"Failed to fetch vm statistics");
        return 0;
    }
    /* Stats in bytes */
    natural_t mem_free = vm_stat.free_count * pagesize;
    return mem_free;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Set up the edit and add buttons.
    self.navigationItem.leftBarButtonItem = self.editButtonItem;

    UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject)];
    self.navigationItem.rightBarButtonItem = addButton;
    [addButton release];

    // Obtain the Managed Object Context
    NSManagedObjectContext *context = [(id)[[UIApplication sharedApplication] delegate] managedObjectContext];

    // Check the free memory before we start
    NSLog(@"INITIAL FREEMEM: %d", [RootViewController get_free_memory]);

    // Loop around a few times
    for(int i=0; i<20; i++) {

        // Create an autorelease pool just for this loop
        NSAutoreleasePool *looppool = [[NSAutoreleasePool alloc] init];

        // Check the free memory each time around the loop
        NSLog(@"FREEMEM: %d", [RootViewController get_free_memory]);

        // Create a minimal request
        NSEntityDescription *entityDescription = [NSEntityDescription                                                  
                                              entityForName:@"TestEntity" inManagedObjectContext:context];        
        NSFetchRequest *request = [[NSFetchRequest alloc] init];
        [request setEntity:entityDescription];

        // Perform the fetch
        NSArray *array = [context executeFetchRequest:request error:nil];        
        [request release];

        // Drain the pool - should release the fetched managed objects?
        [looppool drain];

    }

    // Check the free menory at the end
    NSLog(@"FINAL FREEMEM: %d", [RootViewController get_free_memory]);

}

Когда я запускаю вышеупомянутое на симуляторе, я получаю следующий вывод (который мне кажется разумным):

2011-06-06 09:50:28.123 renniksoft[937:207] INITIAL FREEMEM: 14782464
2011-06-06 09:50:28.128 renniksoft[937:207] FREEMEM: 14807040
2011-06-06 09:50:28.135 renniksoft[937:207] FREEMEM: 14831616
2011-06-06 09:50:28.139 renniksoft[937:207] FREEMEM: 14852096
2011-06-06 09:50:28.142 renniksoft[937:207] FREEMEM: 14872576
2011-06-06 09:50:28.146 renniksoft[937:207] FREEMEM: 14897152
2011-06-06 09:50:28.149 renniksoft[937:207] FREEMEM: 14917632
2011-06-06 09:50:28.153 renniksoft[937:207] FREEMEM: 14938112
2011-06-06 09:50:28.158 renniksoft[937:207] FREEMEM: 14962688
2011-06-06 09:50:28.161 renniksoft[937:207] FREEMEM: 14983168
2011-06-06 09:50:28.165 renniksoft[937:207] FREEMEM: 14741504
2011-06-06 09:50:28.168 renniksoft[937:207] FREEMEM: 14770176
2011-06-06 09:50:28.174 renniksoft[937:207] FREEMEM: 14790656
2011-06-06 09:50:28.177 renniksoft[937:207] FREEMEM: 14811136
2011-06-06 09:50:28.182 renniksoft[937:207] FREEMEM: 14831616
2011-06-06 09:50:28.186 renniksoft[937:207] FREEMEM: 14589952
2011-06-06 09:50:28.189 renniksoft[937:207] FREEMEM: 14610432
2011-06-06 09:50:28.192 renniksoft[937:207] FREEMEM: 14630912
2011-06-06 09:50:28.194 renniksoft[937:207] FREEMEM: 14651392
2011-06-06 09:50:28.197 renniksoft[937:207] FREEMEM: 14671872
2011-06-06 09:50:28.200 renniksoft[937:207] FREEMEM: 14692352
2011-06-06 09:50:28.203 renniksoft[937:207] FINAL FREEMEM: 14716928

Однако, когда язапустить его на реальном iPhone 4 (4.3.3) я получаю следующий результат:

2011-06-06 09:55:54.341 renniksoft[4727:707] INITIAL FREEMEM: 267927552
2011-06-06 09:55:54.348 renniksoft[4727:707] FREEMEM: 267952128
2011-06-06 09:55:54.702 renniksoft[4727:707] FREEMEM: 265818112
2011-06-06 09:55:55.214 renniksoft[4727:707] FREEMEM: 265355264
2011-06-06 09:55:55.714 renniksoft[4727:707] FREEMEM: 264892416
2011-06-06 09:55:56.215 renniksoft[4727:707] FREEMEM: 264441856
2011-06-06 09:55:56.713 renniksoft[4727:707] FREEMEM: 263979008
2011-06-06 09:55:57.226 renniksoft[4727:707] FREEMEM: 264089600
2011-06-06 09:55:57.721 renniksoft[4727:707] FREEMEM: 263630848
2011-06-06 09:55:58.226 renniksoft[4727:707] FREEMEM: 263168000
2011-06-06 09:55:58.726 renniksoft[4727:707] FREEMEM: 262705152
2011-06-06 09:55:59.242 renniksoft[4727:707] FREEMEM: 262852608
2011-06-06 09:55:59.737 renniksoft[4727:707] FREEMEM: 262389760
2011-06-06 09:56:00.243 renniksoft[4727:707] FREEMEM: 261931008
2011-06-06 09:56:00.751 renniksoft[4727:707] FREEMEM: 261992448
2011-06-06 09:56:01.280 renniksoft[4727:707] FREEMEM: 261574656
2011-06-06 09:56:01.774 renniksoft[4727:707] FREEMEM: 261148672
2011-06-06 09:56:02.290 renniksoft[4727:707] FREEMEM: 260755456
2011-06-06 09:56:02.820 renniksoft[4727:707] FREEMEM: 260837376
2011-06-06 09:56:03.334 renniksoft[4727:707] FREEMEM: 260395008
2011-06-06 09:56:03.825 renniksoft[4727:707] FREEMEM: 259932160
2011-06-06 09:56:04.346 renniksoft[4727:707] FINAL FREEMEM: 259555328

Объем свободной памяти уменьшается каждый раз вокруг цикла пропорционально управляемым объектам, которые я выбираю, например, если я выбираюВ два раза больше объектов, чем объем свободной памяти, сокращается в два раза быстрее, так что я вполне уверен, что управляемые объекты не освобождаются.

Обратите внимание, что извлекаемые объекты очень простые, всего дваатрибуты, строка и 16-битное целое число.В приведенных выше примерах их 1000.Код, который я использовал для их генерации, выглядит следующим образом:

// Create test entities
for(int i=0; i<1000; i++) {
    id entity = [NSEntityDescription insertNewObjectForEntityForName:@"TestEntity" inManagedObjectContext:context];
    [entity setValue:[NSString stringWithFormat:@"%d",i] forKey:@"name"];
    [entity setValue:[NSNumber numberWithInt:i] forKey:@"value"];
}
if (![context save:nil]) {
    NSLog(@"Couldn't save");
}

Если кто-нибудь сможет мне объяснить, что происходит, я буду очень признателен!Эта проблема единственная, которая задерживает выпуск моего приложения.Он прекрасно работает на симуляторе! *

Пожалуйста, дайте мне знать, если есть какая-то дополнительная информация, которую я могу предоставить.

Ответы [ 2 ]

1 голос
/ 08 июня 2011

Doh! Вот момент, когда я выгляжу тупым!

Я установил для NSZombieEnabled значение YES, что означало, что извлеченные данные не были выпущены! Без этого все работает нормально: -)

0 голосов
/ 06 июня 2011

У меня нет устройства MacOs, где я могу сейчас тестировать. Но я вижу, что вы не регистрируете NSFetchRequest для автоматического выпуска.

Я бы попробовал такой подход:

NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
...