Поиск циклических ссылок boost::shared_ptr
-
18-09-2019 - |
Вопрос
Есть ли какие-либо советы / хитрости для поиска циклических ссылок 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 .Теперь у вас есть общий график, который вы можете просматривать и можете использовать на нем алгоритмы обнаружения циклов.Я верю Алгоритм сильно связанных компонентов Тарьяна это могло бы сработать, но теория графов - не мой конек.