Nano Hash - криптовалюты, майнинг, программирование

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

Меня смущает случайный сбой, который я наблюдаю, что, согласно инструменту Zombies, вызвано чрезмерным выпуском некоторых значений словаря. Когда я просматриваю историю объектов для одного из этих чрезмерно выпущенных объектов в «Инструментах», я вижу, что его счетчик сохранения падает прямо с +2 до 0 на одном этапе. (Посмотрите на скриншоты в конце поста). Мне непонятно, как это вообще возможно.

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

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


  • Вам нужно показать содержимое файла CreateMyDictionaryContainingCFTypes(). 16.05.2011
  • Вы правы в том, что объекты CoreFoundation не сохраняются неявно. 16.05.2011
  • Что такое [NSAutoreleasePool new]? 16.05.2011
  • @zoul +[NSObject new] — это метод, возвращающий результат [[self alloc] init]. Другими словами, это просто метод удобства. Чаще всего он используется с NSAutoreleasePool, хотя в основном просто по привычке. 20.05.2011
  • Почему вы не создаете словарь внутри начального блока? 02.06.2011
  • Создает ли CreateMyDictionaryContainingCFTypes объект автоматического освобождения? 10.06.2011

Ответы:


1

Что вы используете в качестве CFDictionaryKeyCallBacks и CFDictionaryValueCallBacks при создании словаря в CreateMyDictionaryContainingCFTypes()? Я могу легко воспроизвести эту проблему, если я передам NULL для обоих, но я не смогу воспроизвести ее, если я передам &kCFTypeDictionaryKeyCallBacks и &kCFTypeDictionaryValueCallBacks.

14.06.2011

2

Наконец-то поймал ошибку — оказалось, что это вовсе не проблема зомби, а несвязанная проблема с повреждением памяти в процедуре декодирования данных base64. Ничего общего с сохранением/освобождением, блоками или GCD. Вздох.

Оглядываясь назад, это должно было быть более очевидным. Тот факт, что моя программа падала вскоре после того, как Instruments сообщил об объекте с избыточным выпуском, должен был быть подсказкой — если бы это действительно была проблема с зомби, вы бы не ожидали краха. (Я думаю?) Скачок счетчика удержания с +2 до 0, вероятно, также предполагает что-то иное, чем просто перевыпуск.

Итак, чему я научился?

  • Не копируйте код без тщательной проверки. Все процедуры преобразования base64 не созданы одинаковыми. (В частности, вызов realloc без использования возвращаемого значения является неправильным, неправильным, неправильным! Жаль, что статический анализатор не отмечает это.)
  • Не полагайтесь исключительно на инструменты — могут быть полезны и другие инструменты, такие как Valgrind. В данном случае Valgrind дал мне более точную информацию.
17.06.2011

3

Блок при копировании будет неявно сохранять любой объект Objective-C в своей области, а затем также неявно освобождать эти объекты при освобождении блока.

CFDictionaryRef — это тип бесплатного моста для NSDictionary, а что касается блоков, то и объектов Objective-C. Это означает, что вам не нужно дополнительно управлять памятью.

Позвольте мне прокомментировать ваш код и отметить порядок оценки.

void doStuff() {
    // 1. myDict must have a retainCount of 1, you named your function Create
    //    and promised so according to Core Foundation men.rules.
    CFDictionaryRef myDict = CreateMyDictionaryContainingCFTypes();

    // 2. dispatch_async will copy your block and retain myDict, since it is in 
    //    scope of the block, myDict has a retainCount of 2
    dispatch_async(myQueue, ^{
        // 4. Block is execute some time later, myDict has a retainCount of 1.
        [someObject receiveDictionary:(NSDictionary*)myDict];

        // 5. Block is done and will be released, along with scoped objects
        //    on exit, retainCount reaches 0, and myDict is released.
    });

    // 3. Release your own copy before function ends, retainCount of 1
    CFRelease(myDict);  // this line causes a crash. The Zombies instrument
}
14.05.2011
  • На самом деле, если объекты CoreFoundation не украшены __attribute__((NSObject)), они не сохраняются неявным образом в блоке при его копировании. (См. clang.llvm.org/docs/Block-ABI-Apple.txt) Как написано, этот код очень быстро дает сбой, потому что словарь освобождается в конце doStuff(). 16.05.2011
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..