Проблема с чрезмерным выпуском для объектов, захваченных блоком; сохранить счетчик сразу с +2 до 0!

, меня сбивает с толку случайный сбой, который я вижу, который, согласно инструменту 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, что приводит к сбою

8
задан Nick Hutchinson 16 May 2011 в 04:59
поделиться