Вопрос об утечке памяти в Objective-C - PullRequest
0 голосов
/ 02 октября 2010

У меня есть программа, которая читает огромный текстовый файл (строка за строкой) и выполняет некоторые строковые операции с каждой строкой перед записью строки в базу данных.

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

Я хотел бы знать, что я делаю. Поэтому я спрашиваю:

  • Почему релиз не освобождает память?
  • Есть ли лучший способ сделать это?

Вот моя тестовая программа

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

int cnt = 0;

while (cnt < 1000000000) {
    NSMutableString *teststr = [[NSMutableString alloc] init];

    teststr = [NSString stringWithString:@"Dummy string just for the demo"];

    cnt++;
    if (cnt % 1000000 == 0) {
        printf("cnt=%i\n",cnt);
    }

    [teststr release];


//      [pool drain];                      // It works when I do this 
//      [[NSAutoreleasePool alloc] init];  // and this

}

[pool drain];
return 0;
}

РЕДАКТИРОВАТЬ: Основываясь на ответах до сих пор, я посмотрел на свою оригинальную программу и изменил программу испытаний:

//teststr = [NSString stringWithString:@"Dummy string just for the demo"];

[teststr appendString:@"Dummy string just for the demo"];

Создает ли это также новую строку? Потому что у меня все еще есть проблемы с памятью. Моя процедура работает так, что я добавляю строку чем-то, но, возможно, начинаю с пустой строки в начале.

Ответы [ 3 ]

2 голосов
/ 02 октября 2010
NSMutableString *teststr = [[NSMutableString alloc] init];

Это выделяет изменчивую строку ....

teststr = [NSString stringWithString:@"Dummy string just for the demo"];

, а затем переопределяет переменную teststr строкой с автоматическим освобождением. Выделенная изменяемая строка теперь недоступна, но все еще имеет счет сохранения +1, поэтому она будет пропущена.

[teststr release];

Это только освободит автоматически выпущенную строку, что приведет к ошибке двойного освобождения в будущем.


Если вам нужна изменяемая строка, управляемая вручную, вы должны использовать

NSMutableString* teststr = [[NSMutableString alloc] initWithString:@"Dummy string just for the demo"];
...
[teststr release];

и не присваивайте teststr напрямую, пока оно не будет освобождено или не будет передано право собственности.

1 голос
/ 02 октября 2010

Вы совершаете одну очень простую ошибку.

  1. Вы должны освободить объект при вызове на нем alloc / init.
  2. Объект автоматически освобождается, если вы получаетеобъект, использующий другие средства (удобные конструкторы, возвращенные объекты методов и т. д.).

Метод stringWithString возвращает новую автоматически высвобождаемую строку, поэтому нет смысла выделять / инициализировать ее.Кроме того, поскольку это автоматически высвобождаемый объект, помогает сливать автоматически освобожденный пул.

Вместо:

NSMutableString *teststr = [[NSMutableString alloc] init];
teststr = [NSString stringWithString:@"Dummy string just for the demo"];

Попробуйте:

NSMutableString *teststr = [NSString stringWithString:@"Dummy string just for the demo"];
0 голосов
/ 10 октября 2010

В приведенном выше примере не было столько проблем с памятью.Моя более сложная программа «вытекла» из памяти, и это произошло из-за следующего оператора, который потреблял память без утечки.

NSString *conv = [dict objectForKey:astring]];

На самом деле это не утечка, а несколько таких утверждений и повторение несколькихсто тысяч вызвало большую проблему.Решение состояло в том, чтобы истощить пул авто-выпуска.Но при сливе пула автоматического выпуска имел место тот недостаток, что использовался и объект словаря (dict), который я использую.

Так что это с этим справилось.Я открыл второй бассейн:

NSAutoreleasePool * pool2 = [[NSAutoreleasePool alloc] init];

NSString *conv = [dict objectForKey:astring]];

/* do something */

[pool2 drain];
...