Ответ 1
Как узнать, где лежит утечка памяти?
Я программирую игровой движок на С++, который также поддерживает Lua.
Мой самый большой ужас: утечка памяти.
Это не похоже на то, что моя игра уже заражена ими, я скорее боюсь, что они выскакивают из земли, как грибы, когда развитие находится на поздней стадии, а проект - огромный и сложный.
Я боюсь их, потому что они кажутся мне чрезвычайно трудными. Особенно в сложных системах. Если мой движок почти закончен, игра бежит и память будет съедена, что я буду делать? Где я начну поиск?
Как узнать, где лежит утечка памяти?
Необработанные указатели являются лишь одной из возможных причин утечки памяти.
Даже если вы используете интеллектуальные указатели, такие как shared_ptr, вы можете получить утечку, если у вас есть цикл - для этого нужно использовать слабый_ptr, чтобы разбить цикл. Использование интеллектуальных указателей не является излечим от утечек памяти.
Вы также можете забыть виртуальный деструктор в базовом классе и получить утечки таким образом.
Даже если нет проблем с удалением новых объектов, длительный процесс может расти (и, по-видимому, течь) из-за фрагментации адресного пространства.
Инструменты, такие как valgrind, очень полезны для обнаружения утечек, но они не всегда будут сообщать вам, где должно быть исправление (например, в случае циклов или объектов, удерживающих интеллектуальные указатели)
Требуется четко определенная модель "время жизни объекта". Каждый раз, когда вы делаете "новое", вам нужно подумать о
Кому принадлежит этот объект кучи? то есть кто отвечает за сохранение этого указателя и позволяет другим "клиентам" ссылаться на него?
Кто несет ответственность за удаление этого объекта? Обычно это # 1, но не обязательно.
Есть ли клиенты этого объекта, срок службы которых больше, чем у этого объекта? Если это правда, и они фактически хранят этот указатель кучи, он будет разыменовывать память, которая больше не "существует". Возможно, вам придется добавить некоторые механизмы уведомлений или перепроектировать вашу модель "время жизни объекта".
Много раз вы исправляете утечки памяти, но затем сталкиваетесь с проблемой №3. Именно поэтому лучше всего подумать о своей модели жизненного цикла объекта, прежде чем писать слишком много кода.
Вы сражаетесь с утечками памяти, никогда не используя исходные указатели. Если у вас есть код с использованием исходных указателей, рефакторинг.
Является ли мой страх перед утечками памяти оправданным?
Короткий ответ - да. Длинный ответ - да, но есть методы сокращения их и, как правило, упрощения. Самая важная из этих вещей, по моему мнению, заключается не в том, чтобы использовать новый/удалить легкомысленно и разработать свою программу для уменьшения или эллиминации как можно большего количества динамического распределения. Вместо того, чтобы выделять память, попробуйте следующее и выделите свою собственную память только тогда, когда вам не нужны эти методы (примерно в порядке, который вам нужно):
Как узнать, где находится память утечка?
Valgrind набор инструментов: Memcheck, Cachegrind, Callgrind, Massif, Helgrind...
Вы также можете попробовать выполнить компиляцию с помощью электрического забора (-lefence для gcc) или ваших компиляторов equivelent. Вы также можете попробовать набор инструментов Intels, особенно если вы пишете многопоточный код или код, чувствительный к производительности (например, Parallel Studio), хотя они дороги.
Нет ли хороших инструментов, которые помогают в поиск источника утечек памяти сегодня?
Конечно, есть. См. Выше.
Теперь, поскольку вы пишете игру, я поделюсь некоторыми своими собственными разработками, связанными с развитием игры:
Надеюсь, что это помогло.
AFAIK Valgrid - это только Linux.
Для Windows у вас есть такие инструменты, как BoundsChecker и Purify.
Если вы используете Visual Studio, библиотека C Runtime (CRT) также предоставляет удивительно простой и полезный инструмент для поиска утечек памяти из коробки. Читайте о _ CrtDumpMemoryLeaks и связанных с ним функциях и макросах.
В основном это позволяет вам получить индексированный дамп утечек памяти при выходе из процесса, а затем позволяет установить точку останова во время выделения утечки памяти, чтобы точно увидеть, когда это произошло. Это контрастирует с большинством других инструментов, которые дают вам только посмертный анализ без возможности воспроизвести события, которые привели к утечке памяти.
Использование этих маленьких драгоценных камней с первого дня дает вам относительное спокойствие, что вы в хорошей форме.
Является ли мой страх перед утечками памяти оправданным?
Если вы пишете код, содержащий их, то абсолютно.
Как узнать, где лежит утечка памяти?
Анализируя код.
Нет ли хороших инструментов, которые помогают найти источник утечек памяти сегодня?
Да, но это все еще не просто.
Хорошей новостью является то, что она совершенно не нужна при правильном дизайне. Унция профилактики стоит тонны лечения: лучшая стратегия борьбы с утечками памяти - это написать код таким образом, чтобы гарантировать, что его нет.
Рискуя выглядеть как самодовольный рывок, которым я, вероятно, являюсь, рассмотрим использование любого языка программирования, разработанного после 1979 года, который не имеет проблем с утечками памяти, повреждением стека кучи кучи или даже управлением памятью. (Любой, кто говорит что-то вроде "Мне нужно, чтобы моя программа была быстрой", вероятно, никогда не слышала о Дональд Кнут.)
Утечки памяти не слишком страшны - но они могут нанести ущерб производительности программы (поэтому избавьтесь от них!).
valgrind --leak-check=full -v ./YOUR_EXECUTABLE
Это даст вам полную проверку утечки и подробный (-v) вывод о том, как память используется в вашей программе.
С уважением,
Деннис М.
По крайней мере, для части Lua вы можете использовать свой собственный распределитель памяти и отслеживать все распределения и освобождать и, следовательно, выявлять любые утечки памяти.
Существуют различные методы отслеживания утечек памяти.
Простейшим является использование макроса и определенного распределителя, который будет хранить функцию, которая выделила это. Таким образом, вы можете отслеживать каждое распределение и видеть, какие из них не удаляются, когда они должны быть. Затем вы можете начать писать unittest и утверждать, что память была освобождена.
Если вы используете предварительно скомпилированные контейнеры все время, это не будет работать, поскольку все распределения будут находиться в контейнерах. Тогда ваши варианты:
Вероятно, есть больше вариантов. Тестирование и использование настраиваемого глобального переопределения new/delete (которое может быть запрошено) должно оказаться полезным, если это позволяет его дизайн.
Кроме того, см. Electronic Arts STL С++ paper для обсуждения того, что нужно сделать в STL/С++ для поддержки правильной разработки игр. (Это, наверное, немного более хардкор, чем ваш движок, но он, безусловно, содержит множество самородков вдохновения и изобретательности.)
Как узнать, где лежит утечка памяти?
Visual Leak Detector для Visual С++ 2008/2010