Память не освобождается правильно?

Мое приложение загружает изображения с URL-адреса в определенном порядке, и пользователь просматривает их. У меня есть приложение, которое предварительно загружает следующее изображение и сохраняет старые изображения в кеше.

Этот кеш в основном представляет собой NSMutableDictionary с ключами, связанными с идентификатором изображения. Каждый объект в кеше также является NSDictionary с URL-адресом, URL-адресом изображения, заголовком и объектом NSData. Когда я загружаю изображение, я добавляю новый объект словаря в кеш с этими элементами. Я храню объект NSData следующим образом: NSData * imgData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: imageurl]]; Затем я добавляю этот объект к объекту дочернего словаря.

Это, очевидно, занимает большой объем оперативной памяти после того, как большое количество фотографий хранится и кешируется, поэтому я отвечаю на предупреждение памяти, очищая весь кеш. Проблема в том, что бы я ни пробовал, оперативная память не освобождается. Объекты исчезают (как и должны), но не возвращают оперативную память. Я пробовал делать следующее:

  • Цикл через словарь кеша, освобождение объекта данных в дочернем словаре, затем, когда все элементы пройдены, удалите все дочерние объекты словаря кеша.
  • Цикл через словарь кеша, освобождение дочернего словаря, удаление всех объектов по завершении
  • Даже удаление всех объектов, затем освобождение всего объекта кеша (затем его воссоздание, потому что его все еще нужно использовать)
  • И другие случайные комбинации освобождения, удаления и т. Д.

Проблема в том, что НИЧТО из того, что я пробовал, не освободило ОЗУ. Что-то я делаю неправильно, освобождая память объектов NSData?


person Andrew M    schedule 27.11.2010    source источник
comment
Какую политику кеширования вы используете при загрузке данных? Подтвердили ли вы (например, с помощью Leaks или Allocations), что память определенно утечка или заброшена?   -  person Chris Gummer    schedule 27.11.2010
comment
На самом деле я не использую кеширование, встроенное в iOS SDK - я управляю своим собственным с помощью NSDictionary, заполненного объектами NSData (которые содержат изображения). Когда я удаляю все объекты из словаря, память не освобождается. Я не уверен, где именно эта память все еще распределяется, но она не освобождается, как я хочу.   -  person Andrew M    schedule 27.11.2010


Ответы (2)


Способ управления памятью в Objective-C заключается в том, что вы получаете право собственности на объект, выделяя / инициализируя, -сохраняя или -копируя его, и отклоняете его, когда он вам больше не нужен, с помощью -release или -autorelease.

Что вы хотите сделать:

1) Создайте объект данных

NSData *imgData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:imageurl]]; 

Теперь вы являетесь владельцем объекта, на который указывает imgData.

2) Добавьте этот объект в свой дочерний словарь

[childDictionary setObject:imgData forKey:@"imgData"];

3) Закройте объект данных. Тебе это больше не нужно. childDictionary он нужен, но это не ваша проблема. childDictionary, как и любой другой объект, отвечает за управление своей собственной памятью и владениями.

[imgData release];

Другой способ сделать это - создать автоматически выпущенную версию объекта данных и добавить ее в словарь.

Затем вам нужно убедиться, что вы правильно управляете памятью childDictionary, а также памятью cache. Например:

1) Создайте автоматически выпущенный дочерний словарь

NSMutableDictionary *childDictionary = [NSMutableDictionary dictionary];

2) Добавьте что-нибудь в childDictionary (как мы это делали раньше)

3) Добавить childDictionary в кеш

[cache setObject:childDictionary forKey:yourKey];

4) Поскольку childDictionary был создан автоматически, вам не нужно (и не следует) выпускать его сейчас, когда он вам не нужен. Он будет автоматически выпущен основным автоматическим пулом позже. Если вы создали свой childDictionary, используя:

NSMutableDictionary *childDictionary = [[NSMutableDictionary alloc] init];

который возвращает объект с retainCount равным 1, тогда вам нужно было бы отказаться от владения сейчас:

[childDictionary release];

Что касается кеша, вы, вероятно, захотите сохранить его в течение длительного времени: скорее всего, это переменная экземпляра любого объекта, который управляет кешем, и он сбрасывается с помощью [cache removeAllObjects], когда вы нажимаете предупреждение о памяти.

Если вы разрабатываете на Mac с использованием сборки мусора, все это бесполезно. Но поскольку вы разговариваете по телефону, вам необходимо знать эти простые правила управления памятью. Мое объяснение действительно упускает из виду многие концепции, с которыми вы должны быть знакомы, поэтому я настоятельно рекомендую вам прочитать документацию Apple по этому поводу.

person Nico    schedule 27.11.2010

Был бы полезен упрощенный пример кода, демонстрирующий эту утечку. Просто из вашего описания, возможно ли, что вызов, который вы используете для добавления imgData в словарь, сохраняет его? Если вы не выпускаете imgData сразу в своем собственном коде, счетчик сохраняемых данных будет равен 2. Когда ваш локальный указатель imgData выйдет за пределы области видимости, произойдет утечка памяти. Однако это просто удар в темноту без образца кода.

person Gene Goykhman    schedule 27.11.2010