Как мне узнать, кто держит shared_ptr <>? - PullRequest
11 голосов
/ 30 июня 2009

Я использую boost :: shared_ptr в моем приложении на C ++. Проблема с памятью очень серьезная, и приложение занимает много памяти.

Однако, поскольку я помещаю каждый новый объект в shared_ptr, при выходе из приложения утечка памяти не обнаруживается.

Должно быть что-то вроде std::vector<shared_ptr<> > пула, содержащего ресурс. Как узнать, кто держит shared_ptr при отладке?

Трудно просматривать код построчно. Слишком много кода ...

Большое спасибо!

Ответы [ 8 ]

21 голосов
/ 30 июня 2009

Вы не можете знать, только взглянув на shared_ptr, где находятся «указатели родного брата». Вы можете проверить, если один unique() или получить use_count(), среди других методов .

12 голосов
/ 07 августа 2009

Широко распространенное использование shared_ptr почти неизбежно приведет к нежелательному и невидимому заполнению памяти.

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

Менее понятна проблема невыпущенных ссылок. Если объект является общим для многих shared_ptrs, то он не будет уничтожен, пока каждый из них не обнулится или не выйдет из области видимости. Очень легко пропустить одну из этих ссылок и в конечном итоге увидеть скрытые в памяти объекты, о которых вы думали, что покончили с ними.

Хотя, строго говоря, это не утечки памяти (все они будут устранены до выхода из программы), они так же вредны и труднее обнаружить.

Эти проблемы являются следствием целесообразных ложных заявлений: 1. Объявление того, кем вы действительно хотите быть единоличным владельцем, как shared_ptr. scoped_ptr будет правильным, но тогда любая другая ссылка на этот объект должна быть необработанным указателем, который можно оставить висящим. 2. Объявление того, что вы действительно хотите использовать в качестве пассивной наблюдательной ссылки, как shared_ptr. Слабый_портр был бы верным, но тогда у вас есть проблемы с преобразованием его в share_ptr каждый раз, когда вы хотите его использовать.

Я подозреваю, что ваш проект - прекрасный пример того рода неприятностей, с которыми эта практика может вас завести.

Если у вас есть приложение с интенсивным использованием памяти, вам действительно нужно одно владение, чтобы ваш проект мог явно контролировать время жизни объекта.

с одним владельцем opObject = NULL; обязательно удалит объект и сделает это сейчас.

с общим владением spObject = NULL; ........ кто знает? ......

7 голосов
/ 28 февраля 2013

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

  1. Адрес выделяемого объекта (на что указывает указатель)
  2. Адреса каждого объекта smartpointer, содержащего ссылку на объект
  3. Соответствующие трассы стека того, когда был создан каждый смарт-указатель

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

Затем у нас есть команда «отслеживание утечек» с двумя функциями: «[повторно] начать отслеживание утечек» (которая очищает всю карту и включает отслеживание, если ее еще нет), и «печать открытых ссылок», которая показывает все выдающиеся ссылки на смарт-указатели, созданные с момента запуска команды «начать отслеживание утечек». Так как вы можете видеть в стеке следы появления этих умных указателей, вы можете легко точно знать, кто удерживает ваш объект от освобождения. Когда он включен, он замедляется, поэтому мы не оставляем его включенным все время.

Это большой объем работы для реализации, но он определенно стоит того, если у вас есть кодовая база, где это часто случается.

3 голосов
/ 30 июня 2009

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

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

3 голосов
/ 30 июня 2009

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

1 голос
/ 07 августа 2009

Я собирался предложить использовать UMDH, если вы находитесь на Windows. Это очень мощный инструмент. Используйте его, чтобы найти ассигнования на транзакцию / период времени, которые вы ожидаете освободить, а затем найдите, кто их удерживает.

Есть больше информации об этом SO ответе Найти утечки памяти, вызванные умными указателями

1 голос
/ 30 июня 2009

Вы очевидно держите ссылки на свои объекты в вашем приложении. Это означает, что вы намеренно храните вещи в памяти. Это означает, что у вас нет утечки памяти. Утечка памяти - это когда память выделяется, и тогда вы не сохраняете ссылку на ее адрес.

По сути, вам нужно посмотреть на свой дизайн и выяснить, почему вы храните в памяти столько объектов и данных, и как вы можете минимизировать их.

Единственная возможность утечки псевдопамяти - это то, что вы создаете больше объектов, чем думаете. Попробуйте поставить точки останова на все операторы, содержащие «новый». Посмотрите, создает ли ваше приложение больше объектов, чем вы думали, и прочитайте этот код.

Проблема на самом деле не столько в утечке памяти, сколько в дизайне вашего приложения.

0 голосов
/ 01 июля 2009

Невозможно определить, какие объекты имеют shared_ptr изнутри программы. Если вы работаете в Linux, одним из надежных способов отладки утечек памяти является инструмент Valgrind - хотя он не будет напрямую отвечать на ваш вопрос, он сообщит, где была выделена память, что обычно достаточно для устранение проблемы Я полагаю, что в Windows есть сопоставимые инструменты, но я не знаю, какой из них лучше.

...