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];
Другие вопросы по тегам