Управление памятью в Objective-C и установка указателей на ноль - PullRequest
5 голосов
/ 09 января 2010

Будет ли указатель на объект переходить на nil, когда его счетчик становится равным 0 или когда вызывается dealloc? Почему или почему нет?

Ответы [ 4 ]

13 голосов
/ 09 января 2010

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

Если вы хотите убедиться, что он установлен в ноль, вы должны сделать это самостоятельно.

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

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

5 голосов
/ 09 января 2010

При нормальной модели памяти с фиксированным выпуском нет. При включенной сборке мусора это происходит, если указатель объявлен как __weak (для объектов Objective-C по умолчанию используется __strong). Сборщик мусора обнулит слабые ссылки для вас, когда они удаляются, что делает их идеальными для указания на делегаты и полупереходные объекты. См. Также NSPointerArray , NSMapTable и NSHashTable и их поддержку слабых отношений. (ПРИМЕЧАНИЕ. Нужно понимать, что слабая ссылка не помешает объекту собирать мусор; она обнуляется, когда никакие строгие ссылки не указывают на один и тот же адрес. См. этот документ для краткого описания этого поведения. )

Есть много других преимуществ для сборки мусора в Objective-C, и я искренне рекомендую использовать его, если вы можете. (Он доступен в OS X 10.5+, но не в iPhone OS.) Улучшения производительности в Snow Leopard являются наиболее впечатляющими, и с самого начала он был быстро запущен.

Как говорится, @ darren имеет хорошее замечание: обычно хорошей практикой является обнуление ваших собственных переменных при освобождении их содержимого. Если вы хотите избежать висячих указателей на перевыпущенные объекты, лучше всего взять привычку обнулять переменную самостоятельно. Это не повлечет за собой времени выполнения, и это читабельно. Что еще более важно, установка переменных в nil помогает системе сбора мусора работать наиболее эффективно, поскольку она указывает на память, которую можно безопасно восстанавливать. Код также будет отлично работать в обоих режимах.

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

2 голосов
/ 09 января 2010

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

1 голос
/ 09 января 2010

Подумайте об этой ситуации:

void *p = malloc (100);

while (someCondition)
{
    //  do something with p
}

free (p);

// p is not set to NULL for you, it still points to where it always did

Аналогичным образом, когда объект Objective C освобождается, все указатели на этот объект все еще указывают на то, где он был. Это приводит к ошибкам, когда другой объект размещается в том же пространстве (или даже если в том же пространстве ничего не размещено).

...