MutableCopy AllocLeak MemoryLeak
У меня есть NSTimer, который срабатывает один раз в секунду.
И каждую секунду у меня есть NSString, который должен быть изменен.
Я никогда раньше не пытался иметь дело с управлением памятью, поэтому я не уверен, что то, что я делаю, правильно, но инструменты говорят в "alloc", что строка кода с stringByReplacingOccurrencesOfString
около 45 МБ "живых байтов" примерно через минуту...
(и количество активных байтов продолжает расти с каждой секундой и в конечном итоге приводит к сбою приложения).
Я думаю, что моя проблема лежит где-то с MutableCopy
код?
Вот мой код:
-(void)myTimer {
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
testedit = [[NSString alloc] initWithFormat:@"example"];
withString1a = [[NSString alloc] initWithFormat:@"e"];//this string gets its values randomly from an array in my real code
forString1a = [[NSString alloc] initWithFormat:@"flk34j"];//this string gets its values randomly from an array in my real code
testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];//memory leak /:
}
4 ответа
Вы выделяете память для каждого объекта дважды. Когда вы выделяете второй раз и назначаете его для той же переменной, первый фрагмент выделенной памяти становится недоступным и недоступным.
Затем вы создаете mutableCopy of testit и присваиваете копию переменной оригинала. Опять же, вы оставляете кусок недоступной памяти, плавающий вокруг.
Правило управления памятью без ARC: для каждого выделения, нового, копирования или сохранения необходим соответствующий выпуск. У вас есть 6 ресурсов, одна копия и только 3 версии.
Вот некоторые предложения.
Удалите эти дублированные распределения:
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
предположительно testedit
, withString1a
а также forString1a
все iVars. ( Пожалуйста, объявите ваши iVars как автосинтезированные свойства и назовите их как self.testedit... и т. Д., Которые сделают ваш код намного более понятным для переполнения стека).
Убери все это:
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
Предполагая, что это все iVars, правильное место для их освобождения находится в вашем объекте dealloc
метод
по факту withString1a
а также forString1a
могут быть локальными переменными, поскольку вы получаете их содержимое из других источников:
NSString* withString1a = [[[NSString alloc] initWithFormat:@"e"] autorelease];
NSString* forString1a = [[[NSString alloc] initWithFormat:@"flk34j"] autorelease];
Вы можете autorelease
их, поскольку вы не нуждаетесь в них, чтобы торчать после завершения метода.
Эти строки также могут быть написаны:
NSString* withString1a = [NSString stringWithFormat:@"e"];
NSString* forString1a = [NSString stringWithFormat:@"flk34j"];
(-stringWithFormat - это удобный метод, который возвращает автоматически выпущенный объект)
Это оставляет нас с этими двумя линиями.
testedit = [[NSString alloc] initWithFormat:@"example"];
testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a
withString:forString1a] mutableCopy];
Непонятно, почему вы рассматриваете testit как неизменяемую строку в первой строке и непостоянную строку во второй. Вам вообще не нужна изменяемая строка, поскольку вы заменяете testedit
с новой строкой.
self.testedit = [[NSString alloc] initWithFormat:@"example"];
self.testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a
withString:forString1a] copy];
(тебе нужно copy
как stringByReplacingOccurrencesOfString:withString:
возвращает автоматически выпущенный объект, и здесь вы хотите сохранить его)
Последняя часть головоломки - это избавление от вашего _tetedit распределения памяти iVar. Вы делаете это в dealloc
метод вашего объекта:
- (void) dealloc {
[_testEdit release];
[super dealloc];
}
(Обратите внимание, что init
, принадлежность и dealloc
Методы - это три места, где вы не должны ссылаться на iVar, используя синтаксис свойств.)
Все хорошо, но на самом деле вы должны использовать ARC! Вы, вероятно, _far_ более вероятно, будете вносить ошибки памяти, чем если бы вы полагались на компилятор для управления памятью для вас.
Я хотел бы предложить вам использовать @property
Вот.
В файле.h объявите свойства как:
@property (nonatomic, retain) NSString *testedit;
@property (nonatomic, retain) NSString *withString1a;
@property (nonatomic, retain) NSString *forString1a; //if required write the @synthesize as well in .m class
Вы можете написать свой метод таймера как:
-(void)myTimer {
self.testedit = @"example";
self.withString1a = @"e";//this string gets its values randomly from an array in my real code
self.forString1a = @"flk34j";//this string gets its values randomly from an array in my real code
self.testedit = [self.testedit stringByReplacingOccurrencesOfString:self.withString1a withString:self.forString1a];
}
В методе dealloc вы можете установить все вышеперечисленные свойства как nil
(self.testedit = nil;
) или сделать релиз на них ([testedit release];
).
Если возможно, попробуйте переключиться на ARC, вам не нужно беспокоиться об управлении памятью. Проблема с вашим кодом заключалась в том, что вы используете много операторов alloc / init, не освобождая переменную перед этим. Это приводит к потере ссылки на эту переменную, и вы потеряете ее. Вам не нужно так много операторов распределения. Для каждого выделения или сохранения должен быть соответствующий оператор деблокирования / автоматического деблокирования.
Вы получаете утечку памяти, потому что вы никогда не выделяете testedit
, Всякий раз, когда вы вызываете alloc, это означает, что вам нужно освободить его. Обычно это просто означает release
,
Вместо этого сделайте что-то подобное, затем обязательно освободите выделенную память:
NSString* newString = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];
Если вы используете ARC, у вас не должно быть проблем. Если вы не используете ARC, вы можете попробовать добавить autorelease
:
testedit = [[[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy] autorelease];