Память предупреждение и сбой: как с этим справиться - PullRequest
7 голосов
/ 04 марта 2010

Я использую инструменты, чтобы увидеть утечки памяти. По крайней мере, в одном сценарии, где я постоянно перелистываю слайды / страницы (внутри UIScrollView), я не вижу утечки памяти. Использование инструментов - в разделе «Срок службы распределения» я переключаюсь в режим просмотра «Создано и еще жив» и вижу память объемом около 1,17 МБ. Я предполагаю, что это означает, что мое приложение использует только столько фактической памяти, а остальное перерабатывается должным образом.

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

Если я не использую много памяти и у нее нет утечки памяти, почему я получаю предупреждение о памяти? Поскольку я ничего не могу выпустить, я не вижу способа избежать крушения. Кто-нибудь сталкивался с такой ситуацией или знает, что я могу сделать? Я что-то неправильно истолковываю из Инструментов? Большое спасибо за любой комментарий.

Ответы [ 5 ]

11 голосов
/ 07 марта 2010

В документации сказано:

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

Таким образом, каждое изображение, которое вы загружаете с помощью imageNamed:, будет продолжать существовать в кэше после того, как вы освободите свое последнее владение им.

Приборы не показывают это как утечку, потому что, строго говоря, это не так: что-то (UIImage) все еще знает об этих изображениях. Инструмент «Утечки» покажет утечку только для объекта, который существует, но о котором ничего не известно.

Вы все еще можете увидеть это в Инструментах.

  1. Выберите инструмент ObjectAlloc в документе трассировки и отсортируйте список классов по текущему количеству или по текущему общему размеру. Вы увидите, что большая часть памяти занята объектами UIImage.
  2. Если навести указатель мыши на столбец с именем класса для строки UIImage, вы увидите значок ➲ (перейти в iTunes-Store); если вы нажмете на это, вы увидите список всех ваших экземпляров UIImage.
  3. Затем, если вы наведите курсор мыши на столбец адреса для строки экземпляра, вы увидите ту же кнопку; на этот раз, нажав на нее, вы попадете в историю этого адреса, включая все создания, удержания, выпуски и освобождение объектов с этим адресом.

    Здесь вы можете увидеть распределение изображения (в пределах класса UIImage, упорядоченного вами на несколько стековых кадров вниз), сохранение (вами) и освобождение (вами). Вы также можете видеть, что он не был выпущен UIImage - кэш +[UIImage imageNamed:] все еще владеет изображением, отсюда и «утечка».

Если вы не хотите, чтобы изображения накапливались подобным образом, загрузите их самостоятельно, используя imageWithContentsOfFile: и -[NSBundle pathForResource:ofType:] метод .

ОБНОВЛЕНИЕ: Я читал, что начиная с iOS 3, UIImage будет очищать свой кеш в (по крайней мере, в некоторых) ситуациях с нехваткой памяти, поэтому это не должно быть такой большой «утечкой», как использовалось быть. Вероятно, вы все равно увидите, как накапливается память, но в конечном итоге вы должны увидеть коллапс кучи. Если вы все еще видите, как накапливается память, и можете доказать, что это вина Apple, вы должны документально подтвердить свои доказательства и сообщить об ошибке .

2 голосов
/ 07 марта 2010

Есть ли у переменной NSZombieEnabled значение Да? Это приведет к тому, что освобожденные объекты сохранятся в памяти, что не позволит вам восстановить память. Поэтому попробуйте отключить его, если он активен.

1 голос
/ 11 марта 2011

Если у вас есть только 3 страницы, я понимаю, что вы повторно используете некоторые элементы.

Без остальной части кода трудно сказать, что происходит, но, возможно, вам следует попробовать освободить объект мультипликации перед созданием нового.

Попробуйте что-то вроде этого:

IImage *image = [UIImage imageNamed:imageFile];

if (cartoon!=nil)
    [cartoon release];

cartoon = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 40.0, 320, 280)];

cartoon.image = image ;
cartoon.backgroundColor = [UIColor brownColor];
1 голос
/ 09 марта 2011

Вы проверили, что вы выпустили все свои объекты IBOutlet? На вашем ресурсе вы должны освободить любой объект IBOutlet, который есть в вашем объекте, даже если у них нет метода синтеза.

У нас похожая проблема, и мы решили ее, выпустив все IBOutlets.

Проверьте этот ответ в Переполнение стека

0 голосов
/ 07 марта 2010

Найден источник проблемы. Это в следующем фрагменте

UIImage *image = [UIImage imageNamed:imageFile];

cartoon = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 40.0, 320, 280)];

cartoon.image = image ;
cartoon.backgroundColor = [UIColor brownColor];

У меня есть сотни изображений и текст на каждой странице, и пользователь может прокручивать их, щелкая пальцем (как в приложении для фотографий iphone). Я только создаю 3 страницы в моем UIScrollView и загружаю / выгружаю (и также освобождаю) все, что я явно выделил. Поэтому, когда речь заходит о выпуске мультфильма, я просто выпускаю мультфильм UIImageView, а не UIImage, думая, что он будет выпущен автоматически.

Но похоже, что он не выпускается автоматически. Мое приложение получает предупреждение из памяти (я не предпринимаю никаких действий), и ОС выгружает мои представления, вызывая сбой.

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

    //UIImage *image = [UIImage imageNamed:imageFile];

cartoon = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 40.0, 320, 280)];

//cartoon.image = image ;
cartoon.backgroundColor = [UIColor brownColor];

Кто-нибудь знает, как обойти эту проблему? Есть ли способ принудительно освободить память из UIImage при появлении предупреждения?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...