Как принять меры против утечек памяти?

Я недавно брал интервью для положения C++, и меня спросили, как я принимаю меры против создания утечек памяти. Я знаю, что не дал удовлетворительный ответ на тот вопрос, таким образом, я бросаю его в Вас парни. Что лучшие пути состоят в том, чтобы принять меры против утечек памяти?

Спасибо!

10
задан Peter Alexander 10 March 2010 в 12:27
поделиться

13 ответов

Какие все ответы дали до сих пор до сих пор: Избегайте необходимости звонить Удалить .

В любое время программист должен вызывать Удалить , у вас есть потенциальная утечка памяти. Вместо этого сделайте Delete Вызов автоматически. C ++ гарантирует, что локальные объекты имеют свои деструкторы, вызванные, когда они выходят из неисправности. Используйте эту гарантию, чтобы убедиться, что ваши распределения памяти автоматически удаляются.

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

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

Конечно, в зависимости от использования различные семантики могут быть вызваны. Вам просто нужен простой чехол, где выделение должно длиться до тех пор, пока живет класс обертки? Затем используйте BOOST :: SCOPED_PTR или, если вы не можете использовать Boost, STD :: Auto_ptr . У вас есть неизвестное количество объектов, ссылающихся на распределение без знаний о том, как долго каждая из них будет жить? Тогда ориентированные сосредоточенные Boost :: Shared_PTR - это хорошее решение.

Но вам не нужно использовать умные указатели. Стандартные контейнеры библиотеки тоже делают трюк. Они внутренне выделяют память, необходимую для хранения копий объектов, которые вы ввели в них, и они снова отпускают память, когда они удаляются. Таким образом, пользователь не должен вызывать либо NEW , либо удалить .

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

Но то, что все они общего имеют ответ на ваш вопрос: Raii Raii idiom: приобретение ресурсов инициализация. Распределение памяти - это своего рода ресурс. Ресурсы должны быть приобретены, когда объект инициализируется и выпущен объектом iTryf, когда он разрушен.

Сделайте C ++ области и пожизненные правила выполнять вашу работу для вас. Никогда не звоните Удалить За пределами объекта Raii, будь то класс контейнера, умный указатель или некоторая специальная обертка для одного распределения. Позвольте объекту обрабатывать ресурс, назначенный ему.

Если все Удалить Вызывы, вызовывают автоматически, вы не можете их забыть. И тогда вы не можете утерить память.

21
ответ дан 3 December 2019 в 13:13
поделиться

Очень хороший способ - использовать умные указатели, boost / tr1 :: shared_ptr. Память будет освобождена, как только интеллектуальный указатель (выделенный стек) выйдет за пределы области видимости.

1
ответ дан 3 December 2019 в 13:13
поделиться
  • Умные указатели.
  • Управление памятью.
  • Замените «новый» и «удалить» или используйте свои собственные макросы / шаблоны.
0
ответ дан 3 December 2019 в 13:13
поделиться

Я начинаю с прочтения следующего: https://stackoverflow.com/search?q=%5BC%2B%2B%5D+Memory+Leak

1
ответ дан 3 December 2019 в 13:13
поделиться

Не ставить под сомнение решение об использовании 5GLs и т.д., но программирование затруднено .

Джон Скит - программирование жестко
Coding Horror - программирование жестко

5GLs считались тупиковыми в течение некоторого времени.

-121--4180349-

Далее следует: http://iersoy.com/Posts.aspx?PostID=158


Источник: Как встроить флэш-память в XNA в windows mobile

-121--5086254-

Не забудьте сделать ваш деструктор базового класса виртуальным при наличии виртуальных функций.

2
ответ дан 3 December 2019 в 13:13
поделиться

Используйте все виды умных указателей.

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

2
ответ дан 3 December 2019 в 13:13
поделиться

Как заявили другие, в рекурсии нет ничего принципиально менее эффективного. Есть несколько языков, где это будет медленнее, но это не универсальное правило.

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

Случай в точку:

fib 0 = 0
fib 1 = 1
fib n = fib(n-1) + fib(n-2)

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

-121--942471-
  • Смарт-указатели.
  • Управление памятью.
  • Переопределите «new» и «delete» или используйте собственные макросы/шаблоны.
-121--3515214-
  1. ( Easy ) Никогда не позволяйте необработанному указателю владеть объектом (найдите код regexp «\= * new ». Вместо shared _ ptr или scoped _ ptr или даже лучше использовать реальные переменные вместо указателей как можно чаще.

  2. ( Hard ) Убедитесь, что у вас нет циклических ссылок, при этом shared_ptrs указывают друг на друга, используйте weak _ ptr , чтобы разорвать их.

Готово!

3
ответ дан 3 December 2019 в 13:13
поделиться

Заменить новый с помощью Shared_PTR. В основном рай. сделать код исключения безопасным. Используйте возможным stl везде. Если вы используете ссылки, подсчитанные указатели, убедитесь, что они не формируют циклы. Scoped_exit от Boost также очень полезен.

7
ответ дан 3 December 2019 в 13:13
поделиться

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

C ++ позволяет построить объекты на стеке (то есть как добрые локальные переменные). Это связывает создание и разрушение потока управления: объекты создаются, когда выполнение программы достигает его декларации, и объект разрушается при выходе на блок, в котором была сделана эта декларация. Всякий раз, когда выделение нужно соответствовать этот шаблон, а затем использовать его. Это сэкономит вам большую часть неприятностей.

Для других использований, если вы можете определить и документ четкое понятие ответственности, то это может работать нормально. Например, у вас есть метод или функция, которая возвращает указатель на вновь выделенный объект, и вы документе, что вызывающий абонент становится ответственным за в конечном итоге удаления этого экземпляра. Прозрачная документация в сочетании с хорошей дисциплиной программиста (что-то не легко достичь!) Может решить многие оставшиеся проблемы управления памятью.

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

Подсчет справочников работает довольно хорошо во многих ситуациях, но они не могут обрабатывать циклические структуры. Так что для самых сложных ситуаций вы должны прибегнуть к тяжелой артиллерии, то есть сборщик мусора . Один, который ссылается, - это GC для C и C ++, написанного HANS Boehm, и он использовался в некоторых довольно крупных проектах (например, Inkscape ). Точка сборщика мусора состоит в том, чтобы поддерживать глобальный вид на полное пространство памяти, чтобы узнать, будет ли данный экземпляр в использовании или нет. Это правильный инструмент, когда локальные инструменты, такие как ссылочные подсчет, недостаточно. Можно утверждать, что в этот момент следует задать себе, является ли C ++ правильным языком для проблемы под рукой. Мусорная коллекция работает лучше всего, когда язык является кооперативом (это разблокирует множество оптимизаций, которые не выполняются, когда компилятор не знает о том, что происходит с памятью, как типичный компилятор C или C ++).

Обратите внимание, что ни одна из техник, описанных выше, не позволяет программисту перестать думать. Даже GC может пострадать от утечек памяти, поскольку он использует достижение как приближение использования будущего (существуют теоретические причины, которые подразумевают, что это невозможно, в полной общности, чтобы точно обнаружить все объекты, которые не будут использоваться после этого). Возможно, вам все равно придется установить несколько полей в NULL , чтобы сообщить GC, который вы больше не будете доступа к объекту через заданную переменную.

2
ответ дан 3 December 2019 в 13:13
поделиться
  • Убедитесь, что именно вы точно понимаете, как объект будет удален каждый раз, когда вы создаете один
  • , убедитесь, что вы понимаете, кто принадлежит указатель каждый раз, когда он возвращается вам
  • Убедитесь, что ваши ошибки утилизируются объекты, которые у вас есть Создан соответствующим образом
  • как параноик примерно выше
2
ответ дан 3 December 2019 в 13:13
поделиться

Вы бы хорошо прочитать на Raii .

8
ответ дан 3 December 2019 в 13:13
поделиться

На x86 можно регулярно использовать Valgrind для проверки своего кода

.
0
ответ дан 3 December 2019 в 13:13
поделиться

Итерация более эффективна, чем Рекурсия, верно?

Необязательно. Эта концепция исходит из многих C-подобных языков, где вызов функции, рекурсивной или нет, имел большие накладные расходы и создавал новый стековый кадр для каждого вызова.

Для многих языков это не так, и рекурсия одинаково или более эффективна, чем итеративная версия. В настоящее время даже некоторые компиляторы C переписывают некоторые рекурсивные конструкции в итеративную версию или повторно используют кадр стека для последнего рекурсивного вызова.

-121--942457-

вы можете использовать динамический sql


delimiter //; 
create procedure tst() 
begin 
prepare stmp from 'INSERT INTO LOGG SELECT PFILE_Filename FROM PFILE_FILE'; 
execute stmp; 
deallocate prepare stmp; 
end// 
delimiter ;//

вы должны сделать что-то подобное

у вас есть часть sql-запроса

 SELECT * FROM mytable WHERE parametertype IN( 
, затем вы соединяете его со строкой, переданной в качестве параметра «» a «», «» b «», «» c «», «» d «» с помощью функции CONCAT например, в stmp, как описано выше, а затем выполнить stmp -121--4013073-
  1. Не выделяйте память в куче, если это не требуется. Большая часть работы может быть выполнена в стеке, поэтому вы должны делать кучное выделение памяти только тогда, когда вам это абсолютно необходимо.

  2. При необходимости размещения объекта кучи, принадлежащего другому объекту, используйте std:: auto _ ptr .

  3. Используйте стандартные контейнеры или контейнеры из Boost вместо того, чтобы изобретать собственные.

  4. Если у вас есть объект, на который ссылаются несколько других объектов и которым не владеет ни один, в частности, то используйте std:: tr1:: shared _ ptr или std:: tr1:: слабый _ ptr -- в зависимости от того, что подходит для вашего случая использования.

  5. Если ни одна из этих вещей не соответствует сценарию использования, можно использовать delete . Если вам в конечном итоге придется вручную управлять памятью, то просто используйте средства обнаружения утечки памяти, чтобы убедиться, что вы ничего не утекаете (и, конечно, просто будьте осторожны). Но ты никогда не должен на самом деле добраться до этого пункта.

20
ответ дан 3 December 2019 в 13:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: