Я выполнил инструментарий в своем приложении для проверки утечек памяти, поскольку прошло несколько месяцев (по крайней мере) с момента последней проверки, и я добавил новую функцию в свое приложение и произвел рефакторинг некоторого кода. Когда я начал запускать, все выглядело хорошо с первой проверкой (загружен контроллер основного вида, и он имеет 6 кнопок, метку и 6 пользовательских представлений пользовательского интерфейса, которые по сути являются просто метками с некоторыми изображениями), но вторая проверка поразила меня, говоря, у меня было 1460 новых утечек. Это казалось действительно высоким, когда все, что я делал в приложении, это нажимал кнопку, которая нажимала на второй контроллер вида (хотя и не простой, но он тоже не делал ничего особенного).
Взглянув на список утечек, только 7 были помечены как ошибки моего приложения, а остальные 1453 - следующие системные библиотеки:
- AppSupport
- BackBoardServices
- плинтус
- CFNetwork (как? Я даже не делаю никаких сетей ...)
- ColorSync
- CoreGraphics
- CoreUI
- Основание (вероятно, ~ 300 утечек)
- FrontBoardServices
- GraphicsServices
- ImageIO
- ManagedConfiguration
- PrototypeTools
- QuartzCore
- UIFoundation
- UIKitCore (~ 700 утечек, примерно как половина)
- UIKitServices
- libAccessibility.dylib
- libnetwork.dylib
- libsystem_pthread.dylib
- vimage
Чем больше я делаю в приложении, тем больше системных библиотек появляется, и я могу легко добиться нескольких тысяч утечек.
Глядя на все различные трассировки стека, любопытно, что около половины из них (из всех случайных трасс, на которые я смотрел) имеют одинаковые первые четыре или пять вызовов, начиная с функций lookUpImpOrForward
или _objc_msgSend_uncached
, как видно на скриншоте ниже.
Когда я смотрю на утечки, вызванные моим приложением, все они имеют эти пять функций в верхней части трассировки стека, а функции моего приложения чуть ниже них. Когда я дважды щелкаю по своим функциям в трассировке стека, чтобы взглянуть на строки кода, которые распределяют утечку памяти, меня переводят в строки типа
label = [[UILabel alloc] init];
или
CGPoint point = CGPointMake(bottomBar.frame.origin.x + 70,
bottomBar.frame.origin.y);
первый из которых должен быть совершенно безопасным, так как я не делаю ничего необычного в этом классе памяти, и я понятия не имею, как второй может вообще быть вовлечен в утечку памяти, так как он не имеет дело с любые указатели.
Чтобы попытаться сузить причину, я снова побежал и нажал другую кнопку, которая привела меня к контроллеру представления, который ничего не делает при загрузке и содержит только панель навигации, 6 кнопок (4 с изображениями) и 3 метки - довольно минимальный базовый материал. Тем не менее, я получил 828 новых утечек на чеке после нажатия кнопки.
В дальнейшем я создал совершенно новый проект приложения с одним представлением в Xcode и продублировал первый контроллер представления. Я поместил кнопку на первом контроллере представления, у которого было шоу-шоу второму, и я поместил метку на втором контроллере представления. Вы можете найти код в https://github.com/AdamNEvans/LeakySampleApp. Запуск этого в инструментах дает мне колоссальные 237 утечек памяти после нажатия на контроллер второго вида. Как?!?!?
Я не помню, чтобы когда-либо видел почти столько утечек, когда выполнял инструментарий утечки памяти в прошлом. Я уверен, что я делаю что-то не так, что вызывает по крайней мере некоторые из этих утечек, но тот факт, что их так много и так много не включают в себя мой код, заставляет меня думать, что я либо создаю объекты неправильно в кучу разных мест (я не уверен, как я могу испортить вызовы alloc
и init
), или ошибка была введена в системные библиотеки и наносит ущерб (мое предположение было бы что-то в этих общих пяти функционирует на вершине лота следов стека).
90% утечек меньше 1 КБ, поэтому приложение может выжить в течение длительного времени с этими утечками, но это по-прежнему беспокоит меня, поскольку это служебное приложение, в котором люди могут потенциально проводить часы.
У меня включен ARC, и я использую Xcode 10.2.1, когда запускаю свое приложение на физическом iPad Air 2 с iOS 12.2.
Есть идеи?