Как отладить серьезные проблемы с памятью в простом приложении - PullRequest
3 голосов
/ 05 марта 2019

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

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

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

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

Я прочитал несколько уроков и попробовал некоторые решения, но ничего не помогло. Включено: 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/

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

1 Ответ

2 голосов
/ 05 марта 2019

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

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

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

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

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

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

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

    Например, изображение 100x100 в масштабе 3x займет 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, но методы, изложенные там, по-прежнему применимы, если вы хотите освоить инструменты. Но, как я уже сказал, я думаю, что вы уже определили проблему.

...