Как найти реальную причину предупреждения памяти и как ее разрешить в приложении iOS
У меня есть много сообщений, связанных с управлением памятью, ARC, методами управления памятью, такими как autoreleasepool
, и с помощью инструмента инструмента, чтобы определить, какой код вызывает предупреждение о памяти, но в моем случае я не могу определить точную причину.
Основные сведения, которые вы должны знать о приложении:
-
Мы разработали приложение для iPad. В этом случае мы должны использовать в некоторых случаях более 2000 изображений, поэтому при запуске приложения мы не хотим показывать им изображение-заполнитель (требование клиента). Для этого мы использовали SDWebImage
, сохраняли изображения на диске и позже чем мы загружаем изображения оттуда.
-
Есть так много основных анимаций, которые я выполнял как "эффект Gennie", всплывающие окна и так много других основных анимаций.
Мы использовали ARC в нашем проекте, и мы обнаружили, что из-за непредвиденного сбоя приложения сбой памяти.
Мы использовали Инструменты "Распределение" для поиска грязной памяти.
Раньше мы анализировали журналы, и мы сохраняли изображения с помощью SDWebImage
в DISK, он разрешает частое сбой приложения, но все же приложение сбой из-за предупреждения о памяти.
Когда мы углубимся в то, что мы обнаружили, что "Анонимная VM" продолжает включать и не выпускать память, когда какой-либо экранный переключатель в iPad.
Вот скриншот профилирования нашего приложения на устройстве.
![введите описание изображения здесь]()
Любой, пожалуйста, предлагайте советы или методы кодирования или любую идею, с помощью которой мы можем уменьшить нагрузку на память и разрешить предупреждение о памяти.
Любая помощь будет оценена. Спасибо.
Ответы
Ответ 1
Попробуйте Infer, это может быть полезно, оно сообщает о проблемах с утечкой памяти в iOS и C-коде.
Статический анализатор при развертывании в Facebook, где он используется как часть процесса разработки мобильных приложений. Infer нацеливает критические ошибки, такие как исключения нулевого указателя, утечки ресурсов и утечки памяти - проблемы, которые приводят к сбоям или ухудшению производительности в приложениях.
Ответ 2
Похоже, что какой-то объект в вашем приложении не освобождается, вероятно, из-за цикла сохранения. Проверить ссылки на делегаты - это слабые ссылки.
Также проверьте блоки и убедитесь, что сильная ссылка на self не зафиксирована в блоке. Если Object A сохраняет сильную ссылку на Object B, то передает блок, содержащий сильную ссылку на self на объект B, оба объекта потенциально блокируются в цикле сохранения.
Используйте этот синтаксис, чтобы передать слабую ссылку на self:
__weak typeof(self)weakSelf = self;
[doSomethingWithBlock:^() {
__strong typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf) {
return;
}
[strongSelf doSomething];}];
в Swift выполните следующее:
someObject.doSomething() { [weak self] in
self?.doSomething()
}
или использовать [unowned self] - оба создают слабую ссылку на self, в случае [слабого self], self является необязательным
Чтобы все ваши объекты были освобождены как ожидалось, поместите оператор журнала в свои функции dealloc/deinit и проверьте, действительно ли они вызываются.
Ответ 3
Росомаха,
Не сказать, что это абсолютный ответ на ваш вопрос, но может дать вам некоторый намек на решение проблемы.
Мой случай:
Сегодня утром во время отладки сбой памяти, как и в одном из моих приложений для чата, я пришел к аналогичному сценарию. Я также использую SDWebImage для кэширования и загрузки изображений для последующих использования.
Первоначальные наблюдения заставили меня поверить, что это авария из-за SDWebImage. Вскоре я понял, что судорога скорее из-за очень простой проблемы.
Я никогда не проверял, вызван ли мой viewController dealloc
или нет. Поставив точку останова в dealloc
, я понял, что dealloc никогда не вызывался (по разным причинам, которые я разрешил сейчас).
Как и в вашем случае, мой chatViewController, хотя и не загружал 100 изображений, используемых для загрузки 8 - 10 изображений за раз, и крах начал появляться, когда я использовал панорамные изображения, а не обычные изображения.
Вывод:
-
Мой viewController имел сильную ссылку на UIImageView, который загружал тяжелые изображения, и поскольку dealloc никогда не вызывался для моего ViewController, все загруженные изображения никогда не выполнялись, что приводило к сбою памяти.
-
Когда я загружал тяжелые изображения, я выполнял несколько расчетов, чтобы уменьшить размер изображения. Большинство вычислений включало повторное создание изображения из NSData с использованием UIImageJPEGRepresentation. Повторное распределение данных и переменной владельца изображения добавляется к потреблению памяти приложения.
-
Поскольку мой ViewController участвовал в количестве вызовов API, я создал класс справочной службы singleton, к которому я использовал пропускающие блоки соответствия, и я не использовал его самостоятельно в завершающих блоках, переданных методам. Что на самом деле способствовало увеличению количества ссылок ARC и никогда не позволяло моему контроллеру просмотра освободиться.
Способ отладки
-
Как вы уже упомянули в своем вопросе о том, что вы загружаете множество изображений в свой ViewController, убедитесь, что viewController правильно освобожден и освобождает всю память, загруженную всем ImageView, присутствующим в ViewController.
-
Если ваш ViewController dealloc не будет вызван, то как способ проверки (помните не о решении) в viewWillAppear установите для всех свойств изображения imageView значение nil и принудительно очистите загруженную память.
-
Если ViewController dealloc не получает вызов, оказывается виновником, попробуйте найти, где вы отправляете себя как сильную ссылку. Если найдено, попробуйте использовать weak self
.
Я знаю, что это не абсолютный ответ на ваш вопрос. Просто поделитесь своим опытом с вами. Надеюсь, это по крайней мере даст вам подсказку, чтобы решить вашу проблему.
Ответ 4
В WWDC 2012 Сессия 242 Производительность приложений iOS: память, Apple представляет способ обнаружения проблемы памяти с помощью шаблона Allocations инструментов, начиная с 31 мин.
1.
Apple предлагает повторно нажать pop, прежде чем сделать снимок кучи, я предпочитаю push pop только один раз.
Кнопка "Снимок" называется "Mark Generation"
![Кнопка моментального снимка]()
Вы должны сделать снимок несколько раз.
2. ![Рост памяти]()
Если ваша память растет между каждым снимком, вы можете выкопать один из снимков, кроме первого.
![введите описание изображения здесь]()
Сортировка объектов Persitent, вероятно, вы видели вашу проблему ViewController (если вы только нажимаете pop-команду один раз). Или вы можете просто ее искать.
![persitent]()
3. Теперь вы можете копаться в дереве вызовов, находить и исправлять проблемы.
4. Вы можете использовать эту технику не только для push pop viewControllers, но также прокручивать в tableView, выполнять поиск базы данных и любые другие случаи.