2012-05-15 4 views
4

У меня проблема, я не могу понять. Сделали тонны поиска и попробовали около 50 различных вариаций, до сих пор нет кубиков. Вот моя дилемма.NSData память не освобождается - ARC

У меня есть 3 метода. Один вызывается, когда мой объект PageView загружается, другой вызывается всякий раз, когда пользователь вносит изменения, а последний вызывается всякий раз, когда пользователь покидает страницу.

Первый метод:

- (void)captureInitialLinesTexture { 
@autoreleasepool { 
    self.initialLinesTextureCaptured = TRUE; 
    GLubyte *buffer =(GLubyte *) malloc (1024 * 1024 * 4 * sizeof(GLubyte)); 
    glPixelStorei(GL_PACK_ALIGNMENT,1) ; 
    glReadPixels(0, 0, 1024, 1024, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 
    glBindTexture(GL_TEXTURE_2D, [pageTexture name]); 
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1024, 1024, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 
    NSData __autoreleasing *tempData = [NSData dataWithBytes:buffer length:1024*1024*4*sizeof(GLubyte)]; 
    if (textureData == nil) { 
     textureData = [self.pageController.notebookDoc newTextureInPage:self.page]; 
    } 

    [pageTextures addObject:tempData]; 
    if ([pageTextures count] > 5) { 
     [pageTextures removeObjectAtIndex:0]; 
    } 
    textureData.textureData = tempData; 
    textureData.page = self.page; 
    self.page.texture = textureData; 
    self.page.lastLineId = [NSNumber numberWithInt:self.pageController.newLineId - 1]; 
    [self.pageController saveNotebookWithUndo:FALSE]; 
    free((GLubyte*)buffer); 
    } 
} 

Второй метод:

-(void)capturePageTexture { 
@autoreleasepool { 
    GLubyte *buffer =(GLubyte *) malloc (1024 * 1024 * 4 * sizeof(GLubyte)); 
    glPixelStorei(GL_PACK_ALIGNMENT,1) ; 
    glReadPixels(0, 0, 1024, 1024, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 
    NSData __autoreleasing *tempData = [NSData dataWithBytes:buffer length:1024*1024*4*sizeof(GLubyte)]; 
    [pageTextures addObject:tempData]; 
    if ([pageTextures count] > 5) { 
     [pageTextures removeObjectAtIndex:0]; 
    } 
    free((GLubyte*)buffer); 
    } 
} 

И последний способ:

-(void)attemptInstantPageTextureCapture { 
    if ([pageTextures count] > 0) { 
     self.page.texture.textureData = [pageTextures lastObject]; 
     self.page.lastLineId = [NSNumber numberWithInt:self.pageController.newLineId - 1]; 
     [self.pageController saveNotebookWithUndo:FALSE]; 
    } 
    [pageTextures removeAllObjects]; 
    pageTextures = [NSMutableArray arrayWithCapacity:0]; 
} 

Моя проблема с этими переменными NSData * TempData. По какой-то причине один из них случайно зависает после того, как мой PageView ушел (обнаружен через Allocations Instruments).

Если я загружаю PageView, загорается captureInitialLinesTexture. Затем я могу добавить много штрихов для пера и capturePageTexture после каждого удара, сохраняя до 5 переменных NSData в именах NSMutableArray pageTextures. Когда я покидаю PageView, NSMutableArray опустеет.

Теперь вот он получает удар головой в стену. Распределение NSData всегда одного размера, в этом случае 4 МБ. Когда страница загружается, у меня есть 1 4 мб. Если я сделаю штрихи пера, я смогу получить еще до 5. Затем, когда я покидаю PageView, до 5 из 4-х распределений (NSData) освобождаются, но я всегда получаю левый с 1. Если я затем перейду к Call Tree на инструментах, он случайным образом скажет его из этого первого метода или второго метод. Почему у него нет проблем с сбросом 5 NSData, которые хранятся в массиве, но почему-то 1 NSData где-то оставлен в живых. Кроме того, эта тайна NSData происходит из любого метода случайным образом.

Как я уже сказал, я искал и искал и не могу найти решение этой проблемы. 4MB памяти, очевидно, огромна, поэтому любые утечки такого типа будут убивать приложение с течением времени.

Выделение из одной попытки: Allocation from one attempt

Дерева вызовов для этой попытки: Call tree for that attempt

распределения для еще одной попытки: Allocation for another attempt

Дерева вызовов для других попыток: Call Tree for other attempt

Тот же самый точный код срабатывает каждый раз, и каждый раз, когда это случайно, NSData остается в живых. Кто-нибудь знает, что я делаю неправильно? переменными «page» и «textureData» являются NSManagedObjects, если вам интересно.Насколько вещей, которые я пробовал:

Alloc на объектах NSData затем вызвать initWithBytes: длина:

initWithBytesNoCopy: Длина: - не звонить бесплатно ((GLubyte *) буфер);

initWithBytesNoCopy: Length: freeWhenDone: - не вызывал бесплатный ((GLubyte *) буфер);

NSData метод класса версия выше двух попыток

не используется @autoreleasepool

не используется для __autoreleasing вара декларации

делает NSMutableArray pageTextures свойства страницуПоказать

настройки страницуПоказать к nil до того, как он выскочит из стека NavigationController

, итерации через изменяемый массив pageTextures с использованием __strong и установка всех NSData на nil или null.

Как уже упоминалось выше, все это происходит в классе PageView, который является одним из многих в своем роде в пределах PageViewController, который выталкивается, а затем удаляется с навигационного контроллера. После того, как элемент просмотра PageViewController (только супервизл просмотра) выведен из навигационного стека, одно случайное распределение NSData все еще сохраняется.

Любые предложения вообще были бы чрезвычайно оценены! Что касается основных элементов данных, упомянутых выше, код работает точно так, как планировалось. Единственная проблема заключается в том, что sneaky live NSData distribution ... :(

ответ

4

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

Чтобы обойти эту проблему, мы просто сохранили NSData в файле и изменили модель так, чтобы основные объекты данных просто содержали строку пути к файлу (NSString) вместо булевых данных (NSData).

Проблема решена :)

0

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

+0

Да, удаление __autoreleasing не влияет. Такая же проблема сохраняется. Но спасибо за то, что вы пролили свет на ключевое слово. – Kevin

+0

Использование инструментов, которые вы можете распечатать, получает информацию о размещении, сохранении и выпуске объекта, как показано в этом сообщении, -> http://www.markj.net/iphone-memory-debug-nszombie/. Посмотрите, можете ли вы получить это info, потому что это должно многое помочь. – borrrden

1

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

dispatch_async(dispatch_get_main_queue(), ^{ 
    // malloc and whatever other code goes here... 
}); 
Смежные вопросы