Утечка памяти с помощью [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];
}

person SageAMDP    schedule 03.10.2008    source источник


Ответы (5)


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

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

с участием:

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

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

person mmalc    schedule 04.10.2008

Снижение пикового объема памяти

В общем, рекомендуется избегать создания автоматически выпускаемых объектов.

[Большая часть этого абзаца изменена из этого вопроса.] Поскольку вы обычно (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.

person mmalc    schedule 06.10.2008

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

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

person Chris Hanson    schedule 03.10.2008

Конечным источником информации об управлении памятью, связанной с подсчетом ссылок, по-прежнему остается, ИМО, «Держи меня, используйте Я, освободи меня " от Stepwise.

person Community    schedule 04.10.2008

Ваш код правильный; утечки памяти нет.

theData = [NSData dataWithContentsOfFile:inFile];

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

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

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

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

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

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

person titaniumdecoy    schedule 04.10.2008
comment
Это смущает. 1. В представленном коде нет возможности ссылаться на данные вне метода. 2. Пул с автоматическим выпуском не уменьшает счетчик сохранения после того, как метод возвращает, поэтому, если бы вы могли ссылаться на данные вне метода, это привело бы к сбою только в том случае, если бы пул был осушен. - person mmalc; 04.10.2008
comment
Ваш анализ неверен. 1. Данные передаются объекту декодера, который их сохраняет. 2. Да, пул автозапуска действительно уменьшает счетчик ссылок после возврата из метода. Узнайте что-нибудь о Какао, прежде чем давать людям неправильный совет. - person titaniumdecoy; 04.10.2008
comment
Неясно, почему (1) имеет отношение к тому, доступны ли данные вне метода. - person mmalc; 06.10.2008
comment
(2) Проблема не в том, уменьшает ли пул автозапуска счетчик ссылок, это когда - он не делает этого после возврата метода, но (обычно) в конец цикла событий. Поэтому, если бы вы могли получить доступ к данным вне метода, вы могли бы обойтись без сбоев. - person mmalc; 06.10.2008
comment
Подумайте о том, что вы говорите! Если автоматически освобожденный объект может быть освобожден в любой момент во время выполнения метода, в котором он объявлен, его нельзя будет использовать, потому что вы никогда не узнаете, был ли он уже освобожден. Подумай об этом! - person titaniumdecoy; 07.10.2008
comment
Я не говорю, что автоматически освобожденный объект может быть освобожден в любой момент во время выполнения метода, в котором он объявлен; Я заявляю, что ваш ответ вводит в заблуждение, говоря, что объект освобождается после завершения метода. Это не. - person mmalc; 07.10.2008
comment
theData освобождается, когда освобождается пул автозапуска, с которым они связаны. Следовательно, согласно моему предыдущему комментарию, если бы была ссылка на данные вне метода, тогда было бы возможно получить доступ, не обязательно вызывая сбой. - person mmalc; 07.10.2008
comment
Суть в том, что ваш ответ скорее сбивает с толку, чем помогает. - person mmalc; 07.10.2008
comment
На данные нельзя ссылаться вне метода, потому что они объявлены внутри метода. - person titaniumdecoy; 07.10.2008
comment
Читая ваши ответы на другие вопросы, связанные с управлением памятью какао, кажется, что вы твердо понимаете эту тему. Меня озадачивает, почему вам так сложно понять такую ​​простую идею. - person titaniumdecoy; 07.10.2008
comment
Наконец, позвольте мне спросить вас кое-что: если данные не высвобождаются после завершения метода (а это так), вы предполагаете, что они могут быть выпущены во время выполнения метода. Это не тот случай. См. Мой второй комментарий. - person titaniumdecoy; 07.10.2008
comment
Вы поднимаете вопрос о ссылке на данные вне метода в конце своего ответа: если вы отпустите данные в конце этого метода [...] ваше приложение выйдет из строя, когда вы попытаетесь его использовать . - person mmalc; 08.10.2008
comment
Re, когда данные будут выпущены; ваш ответ подразумевает, что он освобождается при выходе из метода; согласно моим предыдущим комментариям, это не так. Он освобождается, когда освобождается пул автозапуска, с которым он связан. Поэтому, если бы вы могли получить доступ к данным вне метода, это могло бы не привести к сбою. - person mmalc; 08.10.2008
comment
Подчеркну: я не предлагаю и не предполагал, что данные могут быть выпущены во время выполнения метода. - person mmalc; 08.10.2008
comment
Да, он освобождается, когда освобождается пул автозапуска, с которым он связан, то есть через некоторое время после возврата метода. - person titaniumdecoy; 08.10.2008
comment
Это не то же самое, что подразумевается в ответе ... Однако вы не объяснили, почему в своем ответе вы в первую очередь говорите о доступе к данным вне метода - как первоначально отмечалось, это просто сбивает с толку. - person mmalc; 08.10.2008
comment
Это только вас сбивает с толку. Я отказываюсь от попыток вам это объяснить. - person titaniumdecoy; 09.10.2008
comment
Опять же, простой факт в том, что ваш ответ в лучшем случае вводит в заблуждение. Пожалуйста, объясните, почему полезно предлагать доступ к данным вне метода. Это приводит к ненужной двусмысленности. - person mmalc; 10.10.2008