2009-06-30 4 views
10

Я использую boost :: shared_ptr в своем приложении на C++. Проблема с памятью действительно серьезная, и приложение занимает большой объем памяти.Как узнать, кто владеет shared_ptr <>?

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

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

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

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

ответ

20

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

1

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

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

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

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

+1

Большое спасибо! Есть около 200 тысяч строк. Так что сложно проверить каждый новый ... есть ли какой-либо макрос компилятора, чтобы активировать функцию проверки ref ref (если такая способность существует). Я уверен, что память вызывает программирование логической ошибки о пулах, но я просто не могу ее найти. – user25749

+3

У вас все еще есть утечки памяти с shared_ptrs. Создайте циклическую ссылку, и она никогда не будет удалена, даже если остальная часть приложения больше не ссылается на нее. Мгновенная утечка памяти! – jalf

+5

Ссылка на объект, который некорректно сохраняется, по-прежнему является утечкой ресурсов. Вот почему программы GC все еще могут иметь утечки, обычно из-за шаблона Observer - наблюдатель находится в списке вместо наблюдаемого и никогда не снимается с него. В конечном счете, для каждого 'add' требуется' remove', так же как 'delete' требуется для каждого' нового'. Точно такая же ошибка программирования, вызывающая точно такую ​​же проблему. «Ресурс» - это действительно пара функций, которые нужно называть равным числом раз с соответствующими аргументами, а «утечка ресурсов» - это то, что происходит, когда вы этого не делаете. –

3

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

+0

Спасибо вам большое! Я действительно использую weak_ptr в качестве наблюдателя ресурсов. Поэтому я знаю, что в памяти имеется большое количество shared_ptr <>. Я уверен, что нет циклов, какой-то модуль плохо разработан, я пытаюсь это выяснить. – user25749

+2

«Решение является слабым указателем.» «Нет, это не так. Решение состоит в том, чтобы рассмотреть дизайн. – curiousguy

+0

@curiousguy: Да, чтобы быть педантичным, решение _real_ для циклического владения - это избежать этого. Однако есть законные проблемы, которые лучше решаются с помощью циклических указателей. В таких случаях: Решение проблемы утечки памяти, вызванное действительно необходимой циклической ссылкой, заключается в использовании 'std :: weak_ptr'. –

3

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

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

+0

То, что вы говорите, состоит в том, что ** для отладки можно использовать ** слабые ссылки **: если слабая ссылка мертва, нам нужно ее использовать, это означает, что у программы есть ошибка. Впервые я вижу, что эта идея четко выражена в ОС - некоторые другие плакаты с использованием 'weak_ptr', похоже, подразумевают, что это инструмент отладки, но они не говорят об этом четко. Замечание: это менее эффективно, чем использование обычного указателя на C++: возможно, нам нужен 'checked_ptr', который может быть определен как' weak_ptr' или как «обычный указатель» умный указатель. – curiousguy

-1

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

11

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

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

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

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

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

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

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

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

с долевой собственностью spObject = NULL; ........ кто знает? ......

+0

«Программист-программист может решить, что один объект нуждается в ссылке на другую в качестве быстрого исправления и не успевает изучить весь код, чтобы увидеть, закрыт ли он циклом.» «Ему не нужно« читать код », , Он должен прочитать ** проектные документы **. – curiousguy

+4

в реальном мире много проектов не имеют концепции проектных документов :) – paulm

+3

@curiousguy Я предпочитаю код для оформления документов, поскольку документы могут лежать, а код компилируется. – M2tM

1

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

Существует более подробная информация об этом SO ответа Find memory leaks caused by smart pointers

5

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

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

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

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

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