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

Я пытаюсь работать с некоторыми низкими условиями памяти с помощью инструментов. Я могу наблюдать за потреблением памяти в мониторе Physical Memory Free до нескольких MB, хотя Allocations показывает, что All Allocations составляет около 3 МБ, а общий байт - 34 МБ.

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

Кстати, он намного стабильнее без инструментов или подключенного отладчика.

У меня есть утечки до почти нет (возможно, до ста байт до сбоя).

Когда я смотрю на Allocations, я вижу только примитивные объекты. И общая память, о которой сообщается, также очень низкая. Поэтому я не вижу, как мое приложение вызывает эти предупреждения с низкой памятью.

Когда я смотрю на кучи с момента запуска, я не вижу там более 3 МБ между базой и суммой всех значений роста кучи.

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

Что я сделал: Я выключил и снова включил устройство, и это значительно улучшило работу. Инструменты не сообщают о предупреждении о низкой памяти. Кроме того, я заметил, что физическая свободная память при запуске была только около 7 МБ перед перезагрузкой и около 60 МБ после перезапуска.

Тем не менее, я вижу очень регулярное (периодическое) падение в Physical Free Memory, падение с 43 МБ до 6 МБ (тогда резервное копирование до 43 МБ). Я хотел бы знать, что это вызывает это. У меня нет никаких таймеров, работающих в этом приложении. (У меня есть некоторый performSelector: afterDelay:, но они не активны во время этих тестов.)

Я не использую ARC.

Ответ 1

средства выделения и инструменты утечки показывают только то, что на самом деле принимают объекты, но не то, что берут на себя их подстилающие неъектные структуры (хранилища резервных копий). Например, для UIImages он покажет, что у вас есть несколько выделенных байтов. Это связано с тем, что объект UIImage принимает только эти байты, но CGImageRef, который фактически содержит данные изображения, не является объектом и не учитывается в этих инструментах.

Если вы этого еще не делаете, попробуйте запустить Отслеживание VM одновременно с запуском инструмента распределения. Это даст вам представление о распределенной памяти типов. Для iOS "грязная память", показанная этим инструментом, является тем, что обычно вызывает предупреждения о памяти. Грязная память - это память, которая не может быть автоматически отброшена системой VM. Если вы видите много CGImages, изображения могут быть вашей проблемой.

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

Наконец, я рекомендую вам прочитать эту статью, в которой объясняется, как все это работает: http://liam.flookes.com/wp/2012/05/03/finding-ios-memory/.

Ответ 2

Разница между физической памятью от VM Tracker и выделенной памятью из "Allocations" обусловлена ​​основными различиями в работе этих инструментов:

  • Выделение отслеживает то, что делает ваше приложение, путем установки крана в функции, выделяющие память (malloc, NSAllocateObject,...). Этот метод дает очень точную информацию о каждом распределении, таком как позиция в коде (стек), количестве, времени, типе. Недостатком является то, что если вы не отслеживаете каждую функцию (например, vm_allocate), которая каким-то образом выделяет память, вы теряете эту информацию.

  • Отслеживание VM проверяет состояние системной виртуальной памяти через регулярные интервалы. Это гораздо менее точный метод, поскольку он просто дает вам общее представление о текущем состоянии. Он работает на низкой частоте (обычно что-то вроде каждых трех секунд), и вы не понимаете, как это состояние достигнуто.

Известным виновником невидимых распределений является CoreGraphics: он использует много памяти при распаковке изображений, рисовании растровых контекстов и т.п. Эта память обычно невидима в инструменте Allocations. Поэтому, если ваше приложение обрабатывает много изображений, вероятно, вы увидите большую разницу между объемом физической памяти и общим распределенным размером.

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

Ответ 3

У меня есть утечки до почти нет (возможно, до ста байт до сбоя).

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

Итак, мое первое предложение: избавиться от этих утечек, хотя они кажутся маленькими и незначительными - это не так.

Я начал испытывать сбой, так как я переместил некоторые операции в отдельный поток с помощью NSOperationQueue.

Есть ли вероятность того, что операция, которую вы переместили в поток, отвечает за пульсирующий пик? Могло ли оно появляться не раз за раз?

Что касается пиков, я вижу два способа их решения:

  • используйте Time Profiler in Instruments и попытайтесь понять, какой код выполняется, пока вы видите повышение пика;

  • выборочно комментировать части вашего кода (я имею в виду: целые части вашего приложения - например, заменить "реального" контроллера базовым/пустым UIViewController и т.д.) и посмотреть, можете ли вы идентифицировать таким образом.

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

Ответ 4

Когда я читаю ваш текст, у меня создается впечатление, что у вас могут быть скрытые утечки. Я мог ошибаться, но вы на 100% уверены, что у вас есть все утечки?

Я помню один конкретный проект, который я делал несколько месяцев назад, у меня была такая же проблема, и никаких утечек в Инструментах. Моя память все возрастала, и я получаю предупреждения о памяти... Я начал регистрировать какой-то важный метод dealloc. И я видел, что некоторые объекты, subviews (UIView) были "протекающими". Но они не были замечены Инструментами, потому что они все еще были привязаны к главному виду.

Надеюсь, это было полезно.

Ответ 5

В инструменте Allocations Instrument убедитесь, что у вас установлен флажок "Только отслеживать активные распределения". См. Изображение ниже. Я думаю, что это облегчает просмотр того, что на самом деле происходит.

enter image description here

Ответ 6

  • Проводите ли Вы анализ проекта? Если есть какие-либо аналитические предупреждения, исправьте их в первую очередь.

  • Используете ли вы материал CoreFoundation? Некоторые из методов CF имеют... странные... взаимодействия с средой выполнения ObjC и управлением памятью (они не должны делать, AFAICS, но я видел какое-то странное поведение с низкоуровневым изображением и манипуляциями с AV, где это кажется как mem используется вне основного процесса приложения - возможно, вызовы ОС используются Apple?)

... NB: в предыдущих версиях iOS также было несколько mem-утечек внутри методов Apple CF. IIRC последний из них был исправлен в iOS 5.0.

  • (StackOVerflow parser отстой: я набрал "3", а не "1" ). Делаете ли вы что-то с большим количеством экземпляров CALayer большого размера/или UIView с помощью CG *, например, пользовательский метод drawRect в UIView? )

... NB: Я видел точное поведение, которое вы описываете, вызванное 2 и 3 выше, либо в CF-библиотеках, либо в системе Apple windowing, когда оно пытается работать с данными изображения, которые были первоначально созданы внутри CF-библиотек - или который нашел свой путь в CALayers.

Похоже, что инструменты НЕ ПРАВИЛЬНО ПРОПУСКАЮТ использование памяти внутри системы CA/CG; эта область немного сложна, поскольку Apple перетасовывает назад и вперед между CPU и GPU, но это разочаровывает то, что использование mem кажется просто "исчезающим", когда оно явно используется!


Заключительная мысль (4. - но SO не позволит мне ввести это) - используете ли вы невидимые RHS инструментов?

Apple hardcoded Instruments всегда отключает себя при каждом запуске (так что вы должны вручную открывать его). Это глупо, так как часть основной информации существует только в баре RHS. Но я работал с несколькими людьми, которые даже не знали, что они существуют:)