, меня сбивает с толку случайный сбой, который я вижу, который, согласно инструменту Zombies, вызван чрезмерным выпуском некоторых значений словаря. Когда я смотрю на историю одного из этих чрезмерно выпущенных объектов в Instruments, я вижу, что его счетчик сохраненных объектов сразу падает с +2 до 0 на одном этапе. (Взгляните на скриншоты в конце поста). Мне непонятно, как это вообще возможно.
Я должен сказать, что я вижу этот сбой только при профилировании с помощью Instruments, поэтому я полагаю, что это может быть ошибка Apple, но, вероятно, безопаснее предположить, что это ошибка пилота, которую Instruments просто раскрывает.
В любом случае, я ' m конструирую CFDictionary, который содержит некоторые объекты Core Foundation (CFStrings и CFNumbers), а затем я преобразовываю его в NSDictionary * и передаю его методу Objective-C. Ниже приводится упрощенная версия моего кода:
// creates a CFDictionary containing some CFStrings and CFNumbers
void doStuff()
{
CFDictionaryRef myDict = CreateMyDictionaryContainingCFTypes();
dispatch_async(myQueue, ^{
[someObject receiveDictionary:(NSDictionary*)myDict];
CFRelease(myDict); // this line causes a crash. The Zombies instrument
// claims a CFString value contained in this
// dictionary has already been freed.
});
}
// ...
- (void)receiveDictionary:(NSDictionary*)dict
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSString* str1 = [dict objectForKey:@"key1"];
NSString* str2 = [dict objectForKey:@"key2"];
NSNumber* num1 = [dict objectForKey:@"key3"];
dispatch_async(myOtherQueue, ^{
[database executeUpdate:@"INSERT INTO blah (x,y,z) VALUES (?, ?, ?)", str1, str2, num1];
});
[pool drain];
}
Я думал, что str1
, str2
и num1
будут рассматриваться как объекты Objective-C и будут следовательно, они будут захвачены и автоматически сохранены, когда блок в -receiveDictionary:
копируется вызовом dispatch_async
, и освобожден, когда этот блок будет освобожден. Действительно, кажется, что эти переменные улавливаются и сохраняются блоком. Однако, исследуя историю объекта для избыточно выпущенной CFString в Instruments, я вижу, что его счетчик ссылок увеличивается при копировании блока. Удивительно, его счетчик удержаний падает с +2 сразу до 0 при освобождении блока (см. снимок экрана в конце сообщения); Я не знаю, как определить по трассировке стека, какой это блок. К тому времени, когда CFRelease
вызывается в словаре в блоке в doStuff ()
, некоторые из его значений уже были освобождены, и программа аварийно завершает работу.
Итак, где же произошла ошибка дополнительный звонок от релиза? Как может счетчик сохранения объекта упасть прямо с +2 до 0, как указывает Instruments?
По прихоти я заставил второй блок сохранить весь словарь, вот так:
dispatch_async(myOtherQueue, ^{
[database executeUpdate:@"INSERT INTO blah (x,y,z) VALUES (?, ?, ?)", str1, str2, num1];
[dict self];
});
Похоже, сбой исчез; инструменты перестают сообщать о зомби, по крайней мере. Хотя я не могу понять, почему это работает; конечно, я просто должен убедиться, что блок сохраняет значения словаря, которые меня интересуют, не весь словарь. Так что же происходит?
Instruments перечисляет следующую историю объектов для зомби CFString со счетчиком удержания объекта. Я включил скриншоты для интересных событий.
# 0 +1 CFString создана
# 1 +2 CFString добавлены в словарь
Выпущен # 2 +1 CFString
# 3 +2 CFString сохраняется, когда блок в -receiveDictionary:
копируется
# 4 +0 Что за ...? Счетчик сохраненных объектов упал прямо с +2 до 0!
# 5 -1 Выпущен CFDictionary, что приводит к сбою