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

У меня есть существующее приложение, в котором я внес некоторые недавние изменения, и я тестировал эти изменения. Приложение работает отлично на каждом iPad, на котором я тестирую его (iOS 4 и iOS 5). После загрузки нескольких (50+) изображений с тяжелыми представлениями в моем приложении я получаю предупреждение о низком уровне памяти, и мои методы viewDidUnload вызываются, и они должным образом игнорируют все их элементы управления, и мой кеш-память в памяти очищается, и приложение продолжается хорошо.

Однако на iPhone 4 и iPhone4 (iOS 5.0.1 и iOS 5.1) я столкнулся с проблемой, когда в моем приложении заканчивается память, даже не получая предупреждение о низкой памяти. После загрузки нескольких разных представлений в конечном итоге появится новое представление и будет в основном пустым, а на консоли я вижу сообщения о распределении памяти, и весь телефон становится неактивным и иногда убивает мое приложение.

Конкретный вид, который это происходит, различен каждый раз, поэтому он не связан ни с одним видом, а с накоплением памяти с течением времени. Я также подтвердил, что у меня нет утечек памяти.

Этот существующий вопрос схож:

Приложение IOS убито для работы с низкой памятью, но не получено предупреждение о сохранении памяти

и этот ответ подсказывает, что это может произойти, если я застрял в цикле, но я уверен, что мой код не застрял в любых циклах. Я просто перебираю из одного вида в другой в UINavigationController и загружает несколько изображений в каждом представлении. Кроме того, другой вопрос был особенно распространен на iPad, где я не вижу эту проблему на iPad, только iPhone.

BTW, я пробовал зарегистрироваться для уведомления о низкой памяти через NotificationCenter и иметь метод applicationDidReceiveMemoryWarning в моем делете приложения и иметь точки останова на обоих и не вызывать. Кроме того, в консоли отладчика также отображается сообщение с низкой памятью.

Любые идеи о том, что может произойти?


Добавлено 27.02.2012:

Интересно, что, когда я тестировал свое приложение на новом iPad, у него есть та самая проблема, что я вижу на iPhone 4 и 4, где уведомление о низкой памяти не получено. Поэтому мне интересно, вижу ли я ту же проблему, что и этот другой поток:

Новый iPad: предупреждения о низкой памяти не отображаются?

но разработчик в этом потоке тестирует приложение только для iPad и поэтому не тестирует и не обнаруживает эту проблему на любых iPhone.

Я провел некоторое тщательное тестирование и имел список устройств, где я получил надлежащее предупреждение о низкой памяти и устройствах, где я его никогда не получал. Пока я вижу проблему только на iOS5 или выше, однако на iPad1 с iOS 5.0 и 5.1 я не вижу проблемы, поэтому это не просто проблема для всех устройств на iOS 5.

Вот список:

Правильное предупреждение о низкой памяти

iPad1 4.2.1
iPad1 5.0
iPad1 5.1
iPad2 4.3.3
iPhone3G 4.2.1
iPod 3G 4.3.3
iPhone4 4.3.3

Предупреждение о низкой памяти

iPhone4 5.1
iPhone4s 5.0.1
iPad3 5.1

Ответ 1

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

Вы не говорите, где находятся все эти изображения - надеюсь, вы напишете их в файловую систему, а затем загрузите их в представления, используя [UIImage imageWithContentsOfFile] (или используя CGImageRefs, а затем используйте CGImageSourceCreateWithURL). То, что вы хотите избежать, - это иметь изображения в памяти (без обмена в iOS!).

в моем случае у меня была некоторая память mmap для хранения изображений, я даже отключил память (которая синхронизирует ее с файловой системой), но так как синхронизация занимает так много времени, меня "заряжали" для этой несинхронизированной памяти. Я сделал по существу вызов fcntl (fd, F_FULLSYNC) для каждого из этих файлов, чтобы заставить систему очистить каждый блок до того, как я продолжу.

Ответ 2

Я работаю над приложением с множеством больших изображений на iPad 3.

Если я устанавливаю iOS 5.0 в качестве цели развертывания, applicationDidReceiveMemoryWarning не вызывается, если приложение потребляет слишком много памяти, а приложение вылетает.

Однако applicationDidReceiveMemoryWarning получает вызов , если я устанавливаю iOS 5.1 в качестве цели развертывания. Таким образом, ОС сбрасывает кеш, содержащий ранее загруженные изображения, и приложение не разбивается.

Основная проблема заключается в том, что я использую UIImage imageNamed: для загрузки моих изображений, если ваши образы широко используются UIImage imageWithContentsOfFile вместо этого, так что они не получают кеширование (что является проблемой, если размер @2x очень большой).

Обратите внимание, что если я очень быстро отображу много изображений, applicationDidReceiveMemoryWarning не будет вызван вовремя в iOS 5.1, и я сбой!

Ответ 3

Можете ли вы попробовать запустить Инструменты для инструмента "Time Profiler"? Это скажет вам, если вы связаны с процессором в другом потоке (хотя, если вы не создадите их самостоятельно, я буду удивлен, если это произойдет). Также хорошо использовать инструмент "Распределения", если это не показывает курящее оружие.

Ответ 4

Я нашел точное поведение на iPad 3 под управлением iOS 5.1. applicationDidReceiveMemoryWarning не вызывается или NSNotifications для UIApplicationDidReceiveMemoryWarningNotification. Я также тестировал один и тот же код на некоторых других устройствах, поэтому вы можете добавить их в свой список:

Правильное предупреждение о низкой памяти

iPad 2 5.0.1
iPad 2 4.3.5
iPhone 3GS 5.0.1

Предупреждение о низкой памяти

iPad 3 5.1

Паттерн может быть: iOS-устройства с 512 МБ или 1 ГБ оперативной памятью 5.0.1 - 5.1.

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