Может ли число объектов Objective-C упасть ниже нуля?

Я изучил ручное управление памятью в Objective-C, и в каждой статье говорилось: «Когда счетчик сохранения объекта падает до 0, вызывается метод Dealloc, и объект уничтожается». И ничего более.

Но нет ответа на несколько вопросов: Могу ли я опустить счетчик удержания ниже 0? Можно ли вызвать [object release] несколько раз подряд до того, как объект умрет, и заставить счетчик сохранения упасть ниже 0? И если я это сделаю, будет ли существовать Вселенная?

Гугл мне ничего не дает, типа: "Зачем вообще задавать этот вопрос? Никого это не волнует. Иди и прочитай еще раз про управление памятью".


person WantToKnow    schedule 27.09.2016    source источник
comment
Попробуйте выполнить поиск по запросу «перевыпустить цель c».   -  person A O    schedule 27.09.2016
comment
На самом деле, я должен был сказать: что произошло, когда вы попробовали это? На ваш вопрос легко ответить экспериментом.   -  person matt    schedule 27.09.2016
comment
Нет, вселенной больше не будет. Где-то вы получите сбой BAD_ACCESS. Вы сами не пробовали? Весьма замечательно, что вы изучаете ручное управление памятью, это поможет вам понять вещи изнутри. Но это довольно небезопасно и в современных проектах не используется.   -  person Cy-4AH    schedule 27.09.2016
comment
Текущая среда выполнения (по крайней мере, на несколько выпусков назад) никогда не сбрасывает счетчик до нуля. Вместо этого, когда он должен был бы уменьшиться до нуля, он просто пропускает эту часть и вызывает dealloc. См. многочисленные вопросы о том, почему retainCount сообщает 1 для объекта dealloced.   -  person Avi    schedule 27.09.2016


Ответы (2)


Если вы вызываете release, когда счетчик удержания равен 1, немедленно вызывается dealloc. Таким образом, количество сохранений даже не достигает 0.

Дальнейшие вызовы release вызовут сбой во время выполнения, поскольку вы будете разыменовывать освобожденный объект.

Так что нет, вселенной не будет в этот момент :)

person Gabriele Petronella    schedule 27.09.2016
comment
Обратите внимание, что счетчик удержания никогда не падает до нуля; среда выполнения не тратит впустую циклы, уменьшающиеся до уничтожения объекта. - person bbum; 27.09.2016
comment
Спасибо за дополнительные подробности @bbum, я обновил ответ! - person Gabriele Petronella; 27.09.2016

Счетчик удержания может быть равен 0 или выше, но не меньше. Когда объекту выделяется память кучи (alloc init), для счетчика сохранения устанавливается значение 1. Затем вы можете увеличить счетчик сохранения, вызвав для него retain (насколько мне известно, неограниченное количество раз, но я могу ошибаться).

Вызов release просто уменьшил счетчик удержания на 1. Затем система периодически проверяет количество сохранения объектов и освобождает все объекты со счетчиком 0.

Вызов release для уже освобожденного объекта аналогичен вызову любого метода для объекта NULL и должен просто возвращать NULL или void. Однако, если вы явно управляете динамической памятью, вы должны ОЧЕНЬ осознавать, что делаете.

Некоторые интересные моменты:

Почему количество сохранений может быть больше 1?

Это делается для того, чтобы объект не освобождался, пока он все еще требуется для чего-то другого. Например. скажем, у вас есть pet owner и vet. Экземпляр pet принадлежит экземпляру owner. owner переходит к экземпляру vet, а vet также становится владельцем pet. В течение определенного периода времени pet имеет двух владельцев и, следовательно, (если retain была вызвана) имеет счетчик удержания, равный 2. Предположим, что owner освобождается до того, как vet завершит работу с pet; если все было сделано правильно, pet не будет освобожден, его счетчик retain просто уменьшится до 1 вызовом release из owner. Затем vet может закончить с pet, вызвать release и pet будет освобожден.

АРК

Я уверен, вы знаете, что все это было заменено Автоматическим подсчетом ссылок. Как разработчики, мы теперь должны просто знать о типе отношений одного объекта с другим.

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

Извиняюсь за очень длинный ответ, но управление памятью является основной частью программирования приложений и очень интересно.

person Rob Sanders    schedule 27.09.2016
comment
Вызов release для уже освобожденного объекта аналогичен вызову любого метода для NULL. Только если указатель действительно установлен на nil. Отправка release освобожденному объекту является ошибкой программиста: поведение undefined. - person jscs; 27.09.2016
comment
Этот ответ начинается очень неправильно. Счетчик удержания никогда не может быть равен 0. Система ничего периодически не проверяет. Вызов метода для освобожденного объекта является поведением undefined и часто приводит к сбою, это вообще не похоже на вызов любого метода для NULL. Аналогия vet/owner/pet уместна. - person bbum; 27.09.2016