Подтвердить что ты не робот

Calling -retainCount считается вредным

Или, почему я не использовал retainCount В летние каникулы

Это сообщение предназначено для запроса подробных рецензий о whys и wherefores этого печально известного метода retainCount, чтобы консолидировать соответствующую информацию, плавающую вокруг SO. *

  • Основы: Каковы официальные причины не использовать retainCount? Есть ли вообще какая-либо ситуация, когда это может быть полезно? Что нужно сделать вместо этого? ** Не стесняйтесь перерабатывать.

  • Исторический/пояснительный: Почему Apple предоставляет этот метод в NSObject протоколе, если он не предназначен для использования? Является ли код Apple полагаться на retainCount для какой-то цели? Если да, то почему он не скрыт где-то?

  • Для более глубокого понимания: каковы причины, по которым у объекта может быть другой показатель удержания, чем предполагается из кода пользователя? Можете ли вы привести какие-либо примеры *** стандартных процедур, которые могут использовать рамочный код, которые вызывают такую ​​разницу? Существуют ли какие-либо известные случаи, когда количество удержаний всегда отличается от ожидаемого нового пользователя?

  • Что-нибудь еще, о чем вы думаете, стоит рассказать о retainCount?


<суб > * Кодеры, которые новичок в Objective-C и Cocoa, часто сталкиваются или, по крайней мере, неправильно понимают схему подсчета ссылок. В пояснениях к учебнику могут указываться значения сохранения, которые (согласно этим объяснениям) поднимаются на один, когда вы вызываете retain, alloc, copy и т.д., И вниз на один, когда вы вызываете release (и на некоторых в будущем, когда вы вызываете autorelease).

Отстойный Cocoa хакер, Крис, мог бы, таким образом, легко получить представление о том, что проверка количества удержания объекта будет полезна при решении некоторых проблем с памятью, и, следовательно, существует способ, доступный для каждого объекта называется retainCount! Крис называет retainCount на пару объектов, и эта слишком высокая, и эта слишком низкая, и что происходит? Итак, Крис делает сообщение на SO: "Что случилось с моим управлением памятью?" а затем рой <b> <big> буквы спускаются, говоря: "Не делай этого! Вы не можете полагаться на результаты". Это хорошо и хорошо, но наш бесстрашный кодер может захотеть более глубокого объяснения.

Я надеюсь, что это превратится в FAQ, страницу с хорошими информационными эссе/лекциями от любого из наших экспертов, которые склонны писать один, что новые Cocoa -heads могут указывать на то, когда они задаются вопросом о retainCount. Суб >

** Я не хочу делать это слишком широким, но здесь могут быть уместны конкретные советы по опыту или документы по проверке/отладке папок сохранения и выпуска.

*** В фиктивном коде; очевидно, что у широкой общественности нет доступа к фактическому коду Apple.

4b9b3361

Ответ 1

Основы: Каковы официальные причины не использовать saveCount?

Управление автозаполнениями является наиболее очевидным - у вас нет способа убедиться, что многие из ссылок, представленных retainCount, находятся в локальной или внешней (во вторичном потоке или в другом потоке локального пула).

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

Причиной обескураживания его использования (на уровне клиента) является двоякое:

1) Значение может варьироваться по многим причинам. Только потоки - причина, чтобы никогда не доверять ей.

2) Вам все равно нужно выполнить правильный подсчет ссылок. retainCount никогда не спасет вас от несбалансированного подсчета ссылок.

Есть ли вообще какая-либо ситуация, когда это может быть полезно?

Фактически вы можете использовать его значимым образом, если вы написали свои собственные распределители или схему подсчета ссылок или если ваш объект жил в одном потоке, и у вас был доступ к любым и всем пулам автозаполнения, в которых он мог существовать. Это также подразумевает вы не будете делиться им с любыми внешними API. Легкий способ имитировать это - создать программу с одним потоком, нулевыми пулами автозапуска и сделать свою ссылку, считая "нормальный" способ. Это маловероятно, что вам когда-нибудь понадобится решить эту проблему/написать эту программу для чего угодно, кроме "академических" причин.

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

Это может быть полезной диагностикой в ​​крайне редких случаях. Его можно использовать для обнаружения:

  • Сдерживание: распределение с положительным дисбалансом в счете удержания не будет отображаться как утечка, если распределение доступно вашей программе.

  • Объект, на который ссылаются многие другие объекты. Одной из иллюстраций этой проблемы является (изменяемый) общий ресурс или коллекция, который работает в многопоточном контексте. Частый доступ или изменения этого ресурса/коллекции могут привести к значительным узкое место в выполнении вашей программы.

  • Уровни авторекламы: автореализация, пулы авторекламы и циклы сохранения/авторекламы - все это связано со стоимостью. Если вам нужно минимизировать или уменьшить использование памяти и/или рост, вы можете использовать этот подход для выявления чрезмерных случаев.

Из комментария к Bavarious (ниже): высокое значение может также указывать недействительное распределение (dealloc'd instance). Это полностью детализация реализации и, опять же, не используется в производственном коде. Сообщение об этом распределении приведет к ошибке при включении зомби.

Что следует делать вместо этого?

Если вы не отвечаете за возврат памяти в self (то есть вы не пишете распределитель), оставьте ее в покое - это бесполезно.

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

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

Еще проще: используйте Инструменты для отслеживания расчётов и подсчета ссылок, а затем проанализируйте счетчик ссылок и вызовы нескольких объектов в активной программе.

Исторический/пояснительный: Почему Apple предоставляет этот метод в протоколе NSObject, если он не предназначен для использования? Является ли код Apple для какой-либо цели полагаться на keepCount? Если да, то почему он не скрыт где-то?

Мы можем предположить, что он общедоступен по двум основным причинам:

1) Правильность подсчета ссылок в управляемых средах. Хорошо, что распределители используют retainCount - действительно. Это очень простая концепция. Когда вызывается -[NSObject release], может быть вызван счетчик ref (если не переопределено), и объект может быть освобожден, если retainCount равен 0 (после вызова dealloc). Все это хорошо на уровне распределителя. Распределители и зоны (в основном) абстрагированы так... это делает результат бессмысленным для обычных клиентов. См. Комментарий к bbum (ниже) для получения подробной информации о том, почему retainCount не может быть равно 0 на уровне клиента, освобождению объекта, последовательностям освобождения и т.д.

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

Для более глубокого понимания: каковы причины, по которым у объекта может быть другой показатель сохранения, чем предполагается из кода пользователя? Можете ли вы привести какие-либо примеры *** стандартных процедур, которые могут использовать рамочный код, которые вызывают такую ​​разницу? Существуют ли какие-либо известные случаи, когда количество удержаний всегда отличается от ожидаемого нового пользователя?

Опять же, специальные схемы подсчета ссылок и бессмертные объекты. NSCFString литералы относятся к последней категории:

NSLog(@"%qu", [@"MyString" retainCount]); 
// Logs: 1152921504606846975

Что-нибудь еще, о чем вы думаете, стоит упомянуть о файле saveCount?

Это бесполезно, как отладочная помощь. Научитесь анализировать анализ утечек и зомби и часто их использовать - даже после того, как у вас есть дескриптор подсчета ссылок.


Обновление: bbum недавно опубликовал статью под названием saveCount бесполезен. В статье содержится подробное обсуждение того, почему -retainCount не используется в подавляющем большинстве случаев.

Ответ 2

Общее правило: если вы используете этот метод, вам лучше быть уверенным, что вы знаете, что делаете. Если вы используете его для отладки утечки памяти, вы делаете это неправильно, если вы делаете это, чтобы увидеть, что происходит с объектом, вы делаете это неправильно.

Есть один случай, когда я его использовал, и нашел его полезным. То есть в кеше общего объекта, где я хотел очистить объект, когда ничего больше не ссылалось на него. В этой ситуации я ждал, пока keepCount не станет равным 1, а затем я могу освободить его, зная, что на него ничего не держится, это, очевидно, не будет работать должным образом в средах с мусором, и есть лучшие способы сделать это. Но это все еще единственный "правильный" вариант использования, который я видел для него, и это не то, что многие люди будут делать.