Использование инструментов для работы с предупреждениями о недостатке памяти - PullRequest
11 голосов
/ 27 февраля 2012

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

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

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

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

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

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

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

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

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

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

Ответы [ 6 ]

19 голосов
/ 05 апреля 2013

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

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

Другая важная концепция - заброшенная память . Это память, которая была выделена, на нее все еще есть ссылка (и, как таковая, не утечка), но она не используется. Примером такого типа памяти является некоторый кэш, который не освобождается при предупреждении памяти. Чтобы выяснить это, используйте анализ кучи. Нажмите кнопку «Mark Heap» на инструменте распределения, выполните некоторые операции, вернитесь к предыдущему пункту в приложении и снова нажмите «Mark Heap». Второй снимок кучи должен показать вам, какие новые объекты были распределены между этими двумя моментами, и может пролить свет на загадку. Вы также можете повторить операцию, имитирующую предупреждение памяти, чтобы посмотреть, изменится ли это поведение.

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

9 голосов
/ 27 февраля 2012

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

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

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

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

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

4 голосов
/ 06 апреля 2013

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

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

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

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

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

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

  1. используйте Time Profiler в инструментах и ​​попытайтесь понять, какой код выполняется, пока вы видите рост пика;

  2. выборочно закомментируйте части вашего кода (я имею в виду: целые части вашего приложения - например, замените «настоящий» контроллер на простой / пустой UIViewController и т. Д.) И посмотрите, сможете ли вы определить виновник этого пути.

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

2 голосов
/ 03 апреля 2013
  1. Запускали ли вы Анализ проекта? Если есть какие-либо предупреждения анализа, сначала исправьте их.

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

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

  1. (Парсер StackOVerflow отстой: я набрал «3», а не «1») Вы делаете что-то с большим количеством экземпляров CALayer большого размера (или UIView с методами CG *, например, пользовательский метод drawRect в UIView? )

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

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


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

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

2 голосов
/ 02 апреля 2013

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

enter image description here

2 голосов
/ 27 февраля 2012

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

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

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

...