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

StackOverflow https://stackoverflow.com/questions/169034

  •  05-07-2019
  •  | 
  •  

Вопрос

Каждый раз, когда я вызываю этот метод, мои 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];
}
Это было полезно?

Решение

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

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

с:

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

Это делает управление памятью decodedList прозрачный.Считается лучшей практикой присваивать переменные экземпляра с помощью метода доступа (за исключением методов инициализации).В вашей текущей реализации, если вы когда-нибудь вызовете 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.

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

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

Источником просвещения в области управления памятью, связанным с refcount, по-прежнему является, IMO, " Обними меня, используй меня, освободи меня " от Stepwise.

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

theData = [NSData dataWithContentsOfFile:inFile];

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top