Утечка памяти со сборкой "мусора" Какао

Я бил головой о стену, пытающуюся выяснять, как у меня была утечка памяти в собравшем "мусор" приложении Какао. (Использование памяти в Мониторе Действия просто выросло бы и выросло бы, и выполнение приложения с помощью инструментов Монитора GC также покажет постоянно растущий график.)

Я в конечном счете сузил его к единственному шаблону в моем коде. Данные загружались в NSData и затем анализировались библиотекой C (байты данных, и длина были переданы в него). Библиотека C имеет обратные вызовы, которые запустили бы и возвратили бы подстроку стартовые указатели и длины (для предотвращения внутреннего копирования). Однако в моих целях, я должен был превратить их в NSStrings и иметь в наличии их некоторое время. Я сделал это при помощи initWithBytes:length:encoding NSSTRING: метод. Я предположил, что это скопирует байты, и NSString управлял бы им соответственно, но что-то идет не так, как надо, потому что это протекает как сумасшедший.

Этот код "пропустит" или так или иначе обманет сборщик "мусора":

- (void)meh
{
    NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"holmes" ofType:@"txt"]];
    const int substrLength = 80;

    for (const char *substr = [data bytes]; substr-(const char *)[data bytes] < [data length]; substr += substrLength) {
        NSString *cocoaString = [[NSString alloc] initWithBytes:substr length:substrLength encoding:NSUTF8StringEncoding];
        [cocoaString length];
    }
}

Я могу поместить это в таймер и просто наблюдать, что использование памяти повышается и с Монитором Действия, а также с инструментом Монитора GC. (holmes.txt составляет 594 КБ),

Это не лучший код в мире, но он показывает проблему. (Я работаю 10.6, проект предназначен для 10,5 - если это будет иметь значение). Я перечитал по документам сборки "мусора" и заметил много возможных ловушек, но я не думаю, что делаю что-либо, очевидно, против правил здесь. Не повреждает спрашивать, все же.Спасибо!

Zip проекта

Вот рис. графа объектов, просто растущего и растущего:

alt text

5
задан Community 8 February 2017 в 14:19
поделиться

1 ответ

Это несчастный край. Пожалуйста, подайте ошибку ( http://bugreport.apple.com/ ) и прикрепите свой отличный минимальный пример.

Проблема в двух разах;

  • Основной контур событий не работает и, таким образом, коллектор не запускается через активность MEL. Это оставляет коллекционер, выполняющий свой обычный фон только на основе пороговых коллекций.

  • Данные хранят данные, прочитанные из файла в буфер Malloc'D, который выделяется из зоны Malloc. Таким образом, у GC приходится распределение - сам объект NSDATA - действительно крошечный, но указывает на что-то действительно большое (распределение Malloc). Конечный результат заключается в том, что порог коллектора не ударяется, и он не собирается. Очевидно, что улучшение этого поведения желательно, но это сложная проблема.

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

Измените свой код к этому, и сборщик собирает объекты данных. Обратите внимание, что вы не должны использовать Collectexhaustlive часто - он ест CPU.

- (void)meh
{
    NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"holmes" ofType:@"txt"]];
    const int substrLength = 80;

    for (const char *substr = [data bytes]; substr-(const char *)[data bytes] < [data length]; substr += substrLength) {
        NSString *cocoaString = [[NSString alloc] initWithBytes:substr length:substrLength encoding:NSUTF8StringEncoding];
        [cocoaString length];
    }
    [data self];
    [[NSGarbageCollector defaultCollector] collectExhaustively];
}

[Self] [данные] сохраняет объект данных в живых после последней ссылки на него.

13
ответ дан 18 December 2019 в 14:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: