Поиск повышения :: shared_ptr циклические ссылки - PullRequest
9 голосов
/ 05 января 2010

Есть ли какие-нибудь советы / рекомендации по поиску циклических ссылок на shared_ptr?

Это пример того, что я пытаюсь найти - к сожалению, я не могу найти цикл в моем коде.

struct A
{
  boost::shared_ptr<C> anC;
};

struct B
{
  boost::shared_ptr<A> anA;
};

struct C
{
  boost::shared_ptr<B> anB;
};

Ответы [ 6 ]

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

Я бы порекомендовал использовать Valgrind . Когда вы закроете процесс, он покажет вам все утечки памяти. Если ваше отключение каким-либо образом не нарушает цикл, любые циклы должны отображаться как утечка памяти, и Valgrind скажет вам, откуда в вашем коде изначально была выделена память.

3 голосов
/ 05 января 2010

Однажды я отвечал за разработку системы кредитного риска (в C ++, хотя это не актуально). Эти вещи - действительно большие графики с распределением рисков в узлах. У нас была простая эвристика, чтобы определить, находимся ли мы в цикле - если мы прошли более 500 раз (я забыл точную цифру - она ​​была настраиваемой), ответ был да. Большинство схем обнаружения циклов полагаются на эвристику, подобную этой.

1 голос
/ 03 февраля 2010

Я использовал комбинацию вышеупомянутых постов. Я использовал профилировщик памяти, придумал несколько подозрительных циклов и сломал их с помощью weak_ptr.

Ранее я использовал встроенное обнаружение утечки памяти ЭЛТ, но, к сожалению, в моем случае есть несколько статических синглетонов, которые не освобождаются до выгрузки модуля, что, я считаю, происходит после жизненного цикла детекторов ЭЛТ. В основном это дает много изверга, которые являются ложными срабатываниями.

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

У меня были подобные проблемы в прошлом - утечки памяти из-за циклических ссылок shared_ptr, которые оставались незамеченными в течение нескольких месяцев.

Остерегайтесь "тайников". У меня есть объект (назовем его «Фабрика»), который обрабатывает элементы («Виджет»). У виджетов было свойство быть A) неизменным и B) иметь shared_ptr<Factory> для своего создателя (он иногда создавал другие виджеты и т. Д.). Все работало нормально, пока я не добавил кэш Widget в Factory - поскольку виджеты были неизменяемыми, имело смысл кэшировать их, чтобы возвращать один и тот же виджет каждый раз, когда его запрашивали. Мой кеш был кешем shared_ptr<Widget>, поэтому мгновенная тихая утечка. Исправления очевидны, поэтому я не буду вдаваться в них.

В конечном итоге я смог опереться на платформу, которую использовал для обнаружения таких утечек памяти из ЭЛТ. CRT в Visual Studio имеет обнаружение утечек памяти и отчеты, которые я включил в своей тестовой программе для предотвращения регрессий:

int main()
{
    // code code code
    // code code code

#ifdef _MSC_VER
    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
    _CrtDumpMemoryLeaks();
#endif
}

GCC, вероятно, имеет аналогичные базовые сообщения об утечках, но я не знаю, что это такое.

0 голосов
/ 05 января 2010

Вы могли бы реализовать некоторый интерфейс отладки, который возвращает список shared_ptrs, принадлежащих этому объекту. Вы должны сделать это для каждого класса, хранящегося в shared_ptr. Теперь у вас есть общий график, который вы можете просматривать, и можете использовать алгоритмы обнаружения циклов на нем. Я считаю, Алгоритм сильно связанного компонента Тарьяна мог бы работать для этого, но теория графов - это не мое счастье.

0 голосов
/ 05 января 2010

Полагаю, самый простой ответ заключается в том, что умные указатели могут сделать для вас столько всего:

Я предлагаю записывать всякий раз, когда вы делаете цикл, (легко, если вы создаете все три объекта одновременно, иначе сложнее ...), а затем проверяете эту запись, где вы удаляете / отменяете связь объектов, или просто периодически, если это невозможно.

...