Как отлаживать серьезные проблемы с памятью в простом приложении

У меня проблемы с памятью в моем приложении, и я пока не нашел способа узнать, какие объекты/классы используют эту память.

Приложение простое, контроллер просмотра с представлением галереи изображений (представление сетки, как в Instagram Explore; представление коллекции с ячейками xib), и когда вы нажимаете на одно из них, вы переходите к следующему экрану, который представляет собой тот же набор изображений, но как вертикальный список (uitableview с ячейками xib). Изображения загружаются асинхронно из Интернета.

Память, используемая приложением, постоянно увеличивается, когда я прокручиваю оба экрана, а также быстрее каждый раз, когда я открываю экран списка. Затем единственный момент, когда используемая память уменьшается (и я имею в виду резко, например, с 1,8 ГБ до 200 МБ), — это когда она достигает предела устройства, а затем проблема возникает снова и снова. Кроме того, иногда системе не удается уменьшить объем используемой памяти, и приложение аварийно завершает работу («Приложение iOS прекращено из-за проблем с памятью»).

Я не думаю, что это проблема макета, я все это проверил, также использовал отладчик графа памяти и нашел там только проблемы с «malloc», которые никуда меня не ведут, ни класса, ни строки, ничего. Кроме того, инструмент «Инструменты» слишком сложен, и я пока не знаю, как с ним справиться.

Я прочитал несколько руководств и попробовал некоторые решения, но ничего не помогло. Сюда включены: https://krakendev.io/blog/weak-and-unowned-references-in-swift, http://iosbrain.com/blog/2018/07/22/finding-memory-leaks-with-the-xcode-memory-graph-debugger-and-fixing-leaks-with-unowned/, https://www.youtube.com/watch?v=1LnipXiSrSM&t=1697s, https://developer.apple.com/videos/play/wwdc2018/416/

Может ли кто-нибудь дать мне другие советы или руководства о том, как правильно отлаживать проблемы с памятью, чтобы узнать их точное происхождение?


person Daniel Z.    schedule 05.03.2019    source источник
comment
Может быть, вы многократно повторно загружаете изображения, воссоздаете объекты или не используете ячейки повторно?   -  person Daniel    schedule 05.03.2019
comment
Похоже, вы неправильно размещаете свои изображения, когда закончите с ними, но никто не сможет вам помочь, пока мы не увидим код.   -  person Dare    schedule 05.03.2019
comment
Спасибо @Daniel, но я использую библиотеку кэширования изображений, поэтому повторная загрузка прекратится, повторное использование ячеек автоматически выполняется представлением таблицы при вызове метода dequeueReusableCell, а воссоздание объекта - это то, что я сейчас изучаю.   -  person Daniel Z.    schedule 05.03.2019
comment
Спасибо @Dare, но что вы подразумеваете под правильным размещением изображений? Я устанавливаю nil в imageView.image каждый раз, когда ячейка используется повторно. И извините, я не могу публиковать код из-за правил моей компании.   -  person Daniel Z.    schedule 05.03.2019
comment
youtube.com/watch?v=m-yCfWOBqAk   -  person slf    schedule 05.03.2019


Ответы (1)


Большинство современных стратегий отладки памяти ориентированы на выявление и разрешение циклов сильных ссылок. Но это не ваша проблема здесь. Тот факт, что большая часть памяти восстанавливается, когда вы сталкиваетесь с нехваткой памяти, указывает на проблемы с кэшированием. Какую бы дальнейшую диагностику вы ни проводили, она, скорее всего, только подтвердит это поведение.

Чтобы решить эту проблему, установите разумные ограничения для ваших кешей и избегайте кешей, которые не дают вам такого контроля (например, UIImage(named:)), и проблема, скорее всего, будет решена. Мы не можем комментировать дальше, не видя, как извлекаются изображения (например, убедитесь, что кеш для URLSession подходит) и как они кэшируются после загрузки (например, сторонние библиотеки асинхронного поиска изображений обычно дают вам контроль над кешем).

И, предполагая, что вы (или ваши сторонние библиотеки) кэшируете, убедитесь, что:

  • Протестируйте свое приложение на симуляторе, вручную выбрав «Отладка» » «Имитировать предупреждение о памяти». Это поможет подтвердить, реагирует ли приложение на нехватку памяти. На основании того, что вы описываете, я думаю, мы уже знаем, что это так, но это хорошая диагностика.

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

  • Вы кешируете исходные полезные данные (объект Data, содержащий сжатый ресурс jpg/png), а не объекты UIImage (которые после использования не сжимаются и могут быть огромными, если вы не будете осторожны), или

  • Если вы кэшируете объекты UIImage, обязательно измените их размер в соответствии с вашим пользовательским интерфейсом.

    Например, изображение 100x100 в 3-кратном масштабе будет занимать 120 КБ, но если изображение имеет размер 1000x1000 пикселей, даже если представление изображения имеет размер всего 100x100pt, несжатое изображение займет 4 МБ, т. е. 4 байта на пиксель, независимо от размера сжатых jpg/png полезных данных. .

  • Если вы используете NSCache, установите countLimit или totalCostLimit.

  • Если вы делаете свою собственную коллекцию (массив или словарь) загруженных изображений, убедитесь, что вы реагируете на нехватку памяти. Например, в Swift:

    NotificationCenter.default.addObserver(forName: UIApplication.didReceiveMemoryWarningNotification, object: nil, queue: .main) { [weak self] _ in
        // do whatever you need to remove your cached objects here
    }
    

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

FWIW, я думаю, вы провели достаточно диагностики, чтобы определить источник проблемы (тот факт, что он очищается из-за нехватки памяти, действительно указывает на проблемы с кэшированием), но если вы хотите изучить инструмент «Распределения» в «Инструментах», проверьте из этих старых видео WWDC Устранение проблем с памятью и Производительность приложения iOS: память. Они старые и ориентированы на Objective-C, но изложенные в них методы по-прежнему применимы, если вы хотите ускорить работу с инструментами. Но, как я уже сказал, я думаю, что вы уже определили проблему.

person Rob    schedule 05.03.2019
comment
Привет @Rob и спасибо за четкий и полезный ответ! Тем временем я решил проблему, она не имела ничего общего с кэшированием изображений, а с циклами сохранения. Я сохранял ссылки на экземпляры даже после того, как мои контроллеры исчезли. Таким образом, сделать эти переменные слабыми было ключом. Хорошего дня! - person Daniel Z.; 08.03.2019
comment
@ДэниелЗ. - Ржунимагу. Это не согласуется с описанным вами поведением (где память извлекалась, когда вы сталкивались с предупреждениями о памяти). В циклах сильной ссылки память не восстанавливается, когда это происходит. Похоже, у вас здесь две совершенно разные проблемы. Но я рад, что вы решили свою проблему к вашему удовлетворению! - person Rob; 08.03.2019