Вопрос

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

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

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

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

struct C
{
  boost::shared_ptr<B> anB;
};
Это было полезно?

Решение 4

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

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

Другие советы

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

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

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

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

В конечном счете я смог опереться на платформу, которую использовал для обнаружения таких утечек памяти из CRT.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 есть аналогичные базовые отчеты об утечках, но я не знаю, что это такое.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top