Утечка памяти с помощью [NSKeyedUnarchiver decodeObjectForKey]

Каждый раз, когда я вызываю этот метод, у меня возникает NSMutableData, и я не могу понять, как его подключить. Счет сохранения данных увеличивается на один после выделения и инициализации декодера, и я понятия не имею, почему. Я застрял с удержанием 2 в конце метода, и попытка его освобождения приводит к сбою приложения.

- (void)readVenueArchiveFile:(NSString *)inFile key:(NSString *)inKey
{
 NSMutableData *theData;
 NSKeyedUnarchiver *decoder;
 theData = [NSData dataWithContentsOfFile:inFile];
 decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
 venueIOList = [[decoder decodeObjectForKey:inKey] mutableCopy];
 [decoder finishDecoding];
 [decoder release];
}
5 ответов

Я бы предложил заменить эту строку:

venueIOList = [[decoder decodeObjectForKey:inKey] mutableCopy];

с:

ListClassName *decodedList = [decoder decodeObjectForKey:inKey];
self.venueIOList = decodedList;

Это делает управление памятью decodedList понятным. Рекомендуется назначать переменные экземпляра с использованием метода доступа (кроме методов init). В вашей текущей реализации, если вы когда-либо вызываете readVenueArchiveFile: второй раз на одном и том же объекте, вы будете течь (как вы, если decodedList уже имеет значение). Более того, вы можете поместить логику копирования в свой метод доступа и забыть об этом, а не вспоминать mutableCopy каждый раз, когда вы назначаете новое значение (при условии, что есть хорошая причина сделать изменчивую копию в любом случае?).


Уменьшение пикового объема памяти памяти

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

[Большая часть этого абзаца изменена с на этот вопрос.] Поскольку вы обычно (1) не имеете прямого контроля над своей жизнью, автореализованные объекты могут сохраняться для сравнительно долгое время и излишне увеличивать объем памяти вашего приложения. Хотя на рабочем столе это может иметь мало значения, на более ограниченных платформах это может быть серьезной проблемой. Поэтому на всех платформах, и особенно на более ограниченных платформах, по возможности вам настоятельно не рекомендуется использовать методы, которые приводят к автореализованным объектам, и вместо этого рекомендуется использовать шаблон alloc/init.

Я бы предложил заменить это:

theData = [NSData dataWithContentsOfFile:inFile];

с:

theData = [[NSData alloc] initWithContentsOfFile:inFile];

затем в конце метода добавьте:

[theData release];

Это означает, что theData будет освобожден до выхода метода. Вы должны в итоге:

- (void)readVenueArchiveFile:(NSString *)inFile key:(NSString *)inKey
{
 NSMutableData *theData;
 NSKeyedUnarchiver *decoder;
 theData = [[NSData alloc] initWithContentsOfFile:inFile];
 decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
 ListClassName *decodedList = [decoder decodeObjectForKey:inKey];
 self.venueIOList = decodedList;
 [decoder finishDecoding];
 [decoder release];
 [theData release];

}

Это упрощает семантику управления памятью и как можно быстрее восстанавливает память.

(1) Вы можете взять управление, используя собственные локальные пулы автоопределений. Подробнее об этом см. Руководство по программированию Apple Memory Management.


Не беспокойтесь о том, чтобы сохранить счет, беспокоиться о балансе внутри метода. То, что вы делаете в этом методе, выглядит корректно, предполагая, что venueIOList - это переменная экземпляра.

Чтобы немного расширить мой ответ: Unarchiver может сохранять ваши данные во время операции unarchive, а затем отправлять данные -autorelease, когда это делается вместо -release. Поскольку это не то, что вы сделали, это не то, о чем вам нужно заботиться.


Конечным источником для просветления памяти, связанного с пересчетом, по-прежнему остается IMO, "Держите меня, используйте меня, бесплатно" из Stepwise.


Ваш код верен; утечка памяти отсутствует.

theData = [NSData dataWithContentsOfFile:inFile];

эквивалентно

theData = [[[NSData alloc] initWithContentsOfFile:inFile] autorelease];

В этот момент у Data есть счетчик ссылок 1 (если меньше, он будет освобожден). Счетчик ссылок будет автоматически уменьшаться в некоторый момент в будущем пулом авторезистов.

decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];

Объект декодера сохраняет ссылку на Data, которая увеличивает счетчик ссылок до 2.

После того, как метод вернется, пул авторесурсов уменьшит это значение до 1. Если вы отпустите Data в конце этого метода, счетчик ссылок станет 0, объект будет освобожден, и ваше приложение выйдет из строя, когда вы попытаетесь используйте его.

licensed under cc by-sa 3.0 with attribution.