Почему это не вылетает?

Почему вторая строка в цикле (a.retainCount) не падает (из-за плохого доступа)?

NSArray* a0 = @[[NSMutableString stringWithString:@"a"]];    
NSArray * arr = [NSArray arrayWithObject:a0];
[a0 release];[a0 release];

for (NSArray* a in arr)
{
    //NSLog(@"%d", (a == a0) );
    NSLog(@"RC: %d", a.retainCount);
}

но это приведет к сбою, если первая строка в цикле (a == a0 one) не будет прокомментирована.

Это определенно приведет к сбою, когда пул автовыпуска будет истощен, но я специально спрашиваю о второй строке цикла, а не после.

Кто-нибудь может объяснить?


person Sohaib    schedule 01.07.2013    source источник
comment
Можете ли вы объяснить, какое это имеет отношение к xcode?   -  person Popeye    schedule 01.07.2013
comment
Это вопрос домашнего задания? Мы здесь не для того, чтобы делать вашу домашнюю работу.   -  person Popeye    schedule 01.07.2013
comment
Почему вы освобождаете объект a0, если он вам не принадлежит? Нет alloc, new или copy, так что вы перевыпускаете его. Это может быть причиной сбоя, когда вы делаете журнал равенства, потому что он указывает на недопустимый адрес памяти.   -  person rckoenes    schedule 01.07.2013
comment
(a == a0) возможно вылетает как sizeof(BOOL) != sizeof(int); int является тем, что ожидает спецификатор формата %d.   -  person trojanfoe    schedule 01.07.2013
comment
на самом деле, я сначала подумал, что это глупый вопрос, но чем больше я на него смотрю, может быть, это не так.   -  person Grady Player    schedule 01.07.2013
comment
@trojanfoe: я думаю, что операторы сравнения оцениваются как int. И даже если нет: в списке переменных аргументов все целочисленные аргументы, меньшие int, повышаются до int.   -  person Martin R    schedule 01.07.2013
comment
@MartinR Да, я думаю, ты можешь быть прав.   -  person trojanfoe    schedule 01.07.2013
comment
он выйдет из строя, если вы поместите его в пул автовыпуска и истощите его ... автоматически выпущенный объект в конечном итоге будет протекать таким образом.   -  person Grady Player    schedule 01.07.2013
comment
Вероятно, это просто эксперимент по изучению того, как работает управление памятью.   -  person Ramy Al Zuhouri    schedule 01.07.2013
comment
Даже если объект освобождается, используемая им память может оставаться допустимой до тех пор, пока она не будет использована для чего-то другого. Первый NSLog() просто вызывает повторное использование памяти.   -  person Martin R    schedule 01.07.2013
comment
@Popeye: я только что добавил xcode, потому что это произошло в xcode :)   -  person Sohaib    schedule 01.07.2013
comment
Это не вопрос домашнего задания. Я обнаружил это, исследуя аварию.   -  person Sohaib    schedule 01.07.2013
comment
@GradyPlayer: я согласен, что он рухнет, когда дойдет до инструкции [выпуск пула]. Но я специально спрашиваю о второй строке в цикле.   -  person Sohaib    schedule 01.07.2013
comment
@MartinR: я не думаю, что первый NSLog вызывает повторное использование памяти. Он просто сравнивает указатели (адреса), как и сравнение 4-байтовых целых чисел.   -  person Sohaib    schedule 01.07.2013
comment
@Sohaib: Но NSLog() - это вызов функции, который использует NSString внутри для форматирования сообщений, так что вполне может привести к повторному использованию и перезаписи любой неиспользуемой памяти.   -  person Martin R    schedule 01.07.2013
comment
@MartinR: Даже если NSLog перезаписывает память, почему без NSLog отображается continueCount 1 ? Разве он не должен показывать 0 ? Кроме того, не должен ли доступ к освобожденной памяти вызывать bad_access (даже если содержимое объектов не повреждено, оно нам просто не принадлежит)? Его основы управления памятью?   -  person Sohaib    schedule 01.07.2013
comment
Нет никакой гарантии, что чрезмерно выпущенный объект вызовет сбой в любой конкретный момент времени. Обычно (когда у вас не включены определенные параметры отладки) вы не получите сбой, пока пространство, принадлежащее объекту, не будет перераспределено для нового использования. Это не может быть причиной, пока вы не нажмете первый NSLog, который создает изменяемый строковый объект для получения отформатированного значения журнала. Затем следующая ссылка на объект (в следующем NSLog) становится габблойной. Обратите внимание, что в общем случае перераспределение может происходить в другом потоке.   -  person Hot Licks    schedule 01.07.2013
comment
@GradyPlayer Это не глупый вопрос, это вопрос, который не требует никаких исследований. -1.   -  person    schedule 01.07.2013
comment
@Sohaib Быстрый поиск в Google по запросу автовыпуска Objective-C без сбоя выдал ссылку на дубликат в качестве самого первого попадания. Не говорите мне, что вы провели исследование перед публикацией, потому что вы явно этого не сделали.   -  person    schedule 01.07.2013
comment
@ H2CO3 автовыпуск не там, где он их выбрасывал, дело в том, что они выбрасывались из-за того, что, не вызывая NSLog, он не затирал память и не давал сбой ...   -  person Grady Player    schedule 01.07.2013
comment
@GradyPlayer все эти удобные методы возвращают объекты с автоматическим освобождением, так что это является обманом.   -  person    schedule 01.07.2013


Ответы (2)


Это может рухнуть в любой момент. Вероятно, первая строка в цикле активировала память по оборванному указателю «a», выделенную для другого использования. Поэтому, когда во второй строке упоминается «а», может произойти что угодно. Если вы включите параметры XCode в «Схема -> Диагностика -> Управление памятью», это может привести к немедленному сбою.

person Joe Smith    schedule 01.07.2013
comment
да. На самом деле любой вызов NSLog вместо DLog(@"%d", (a == a0) ) приводит к сбою следующего оператора. - person Martin R; 01.07.2013
comment
Я только что заменил DLog на NSLog и проверил. Эффект тот же. - person Sohaib; 01.07.2013
comment
@Joe Smith: Какие именно варианты вы имеете в виду? - person Sohaib; 01.07.2013
comment
@Sohaib: Я имел в виду следующее: даже NSLog(@"%d", 42) вызывает сбой в следующей строке. Вызов NSLog вызывает перезапись памяти освобожденного экземпляра. - person Martin R; 01.07.2013
comment
Поведение последовательное. Он должен падать каждый раз, независимо от того, прокомментирована ли первая строка. Но не вылетает при комментировании первой строки. - person Sohaib; 01.07.2013
comment
@MartinR: Хорошее наблюдение, я не проверял. Даже если NSLog перезаписывает память, почему без NSLog он показывает continueCount 1 ? Разве он не должен показывать 0 ? Также не должен ли доступ к освобожденной памяти вызывать bad_access (даже если содержимое объектов не повреждено, оно нам просто не принадлежит)? Его основы управления памятью? - person Sohaib; 01.07.2013
comment
где a разыменован? a==a0 не уважает это - person Grady Player; 01.07.2013
comment
@Sohaib: нет объекта с continueCount 0. Если объект с continueCount 1 освобождается, то объект освобождается, возможно, с использованием free() или чего-то подобного. Это просто означает, что память, ранее занятая объектом, теперь снова доступна для будущих выделений. Но пока страница памяти не будет возвращена системе, память все еще существует и к ней можно получить доступ. - person Martin R; 01.07.2013
comment
@MartinR: Какой continueCount он покажет после того, как мы освободим объект (имея continueCount равным 1 перед выпуском) и до того, как страница (на которой находился объект) будет возвращена обратно в систему? - person Sohaib; 01.07.2013
comment
Счетчики сохранения @Sohaib никогда не достигают 0 внутренне, если они идут на 0, вместо этого они отправляются в дело... нет никакого способа прочитать 0 из счетчика сохранения... - person Grady Player; 01.07.2013
comment
@MartinR, вы должны опубликовать ответ, так как вы правы, я проверил. - person Grady Player; 01.07.2013
comment
@Sohaib: Обмен сообщениями с объектом после того, как он был освобожден, является неопределенным поведением, поэтому объект не должен возвращать значение, когда вы отправляете ему сообщение после того, как он был освобожден. Это все равно, что спросить, как должна пахнуть симфония? Вы не можете почувствовать запах симфонии и не можете отправить сообщение освобожденному объекту. Попытка сделать это приведет к непредсказуемым результатам. - person Chuck; 01.07.2013

person    schedule
comment
+1, я так рад, что кто-то сделал этот веб-сайт ... но я думаю, что ОП, вероятно, начал возиться со счетчиком удержаний, изолируя ошибку (давая им преимущество сомнения). - person Grady Player; 01.07.2013
comment
О, конечно - каждый идет по пути RC по крайней мере пару раз, когда он плохо знаком с окружающей средой (а иногда и когда он не так уж новичок). В этом нет ничего плохого, и понимание того, почему это так бесполезно, дает много второстепенной информации, универсально применимой к другим аспектам разработки iOS/Cocoa. - person bbum; 01.07.2013
comment
@bbum: печать сохранения счетчика была не тем, что меня интересовало. Настоящий интерес заключался в том, почему он не зависал. Возможно, потому что у меня была теория, что как только счетчик сохранения объекта достигает 0, его память отправляется обратно в систему, и после этого вызов его метода должен падать (особенно в случае, если вызываемый метод использует какую-то переменную экземпляра ). - person Sohaib; 01.07.2013
comment
@bbum: Почему отправка сообщения в освобожденный экземпляр является неопределенным поведением? - person Sohaib; 01.07.2013
comment
@Sohaib: Это неопределенное поведение, потому что доступ к освобожденной памяти является неопределенным поведением в соответствии со спецификацией C, и каждое отправляемое сообщение должно иметь доступ хотя бы к первому слову в адресе получателя. - person Chuck; 01.07.2013
comment
Я имел в виду, почему это не всегда ошибка сегментации? - person Sohaib; 01.07.2013
comment
@Sohaib Потому что free() память никак не изменяется. - person bbum; 02.07.2013
comment
@bbum: я спрашиваю, почему отправка сообщения в освобожденный экземпляр не всегда является ошибкой сегментации? - person Sohaib; 02.07.2013
comment
@Sohaib, на этот вопрос уже несколько раз отвечали; когда объект освобождается, для указателя вызывается free(). Память не модифицируется, просто помечается для повторного использования. - person bbum; 02.07.2013
comment
Я думал, что MMU должен вызвать сбой приложения (конечно, через ОС), поскольку к чему-то обращаются за пределами памяти, доступной для приложения. Но похоже, что память остается в собственности приложения даже после его выпуска. - person Sohaib; 13.08.2013
comment
@Sohaib free() (или dealloc) память возвращается в кучу приложения для использования этим приложением. Он не возвращается системе, если имеется достаточно непрерывной свободной памяти, чтобы вся страница памяти не использовалась, и система находится под нехваткой памяти до такой степени, что система восстанавливает память. Даже в этом случае отдельные страницы вряд ли будут восстановлены системой, поскольку фрагментация карты виртуальных машин требует больших затрат и ее обычно избегают. - person bbum; 13.08.2013