Как работают детекторы утечки памяти? Каковы основные концепции в целом? Может взять С++ в качестве языка для объяснения этого.
Принцип работы детектора утечки памяти
Ответ 1
Существует несколько различных способов работы детекторов утечки. Вы можете заменить реализацию malloc
и free
на те, которые могут отслеживать дополнительную информацию при распределении и не связаны с производительностью. Это похоже на то, как работает dmalloc
. В общем случае прописывается любой адрес malloc
'ed, но не free
' d.
Основная реализация на самом деле довольно проста. Вы просто поддерживаете таблицу поиска каждого распределения и номер ее строки и удаляете запись, когда она освобождается. Затем, когда программа будет выполнена, вы можете перечислить всю просочившуюся память. Трудная часть определяет, когда и где должно было быть освобождено выделение. Это еще сложнее, если есть несколько указателей на один и тот же адрес.
На практике вам, вероятно, понадобится больше, чем просто номер одной строки, а скорее трассировка стека для потерянных распределений.
Другой подход заключается в том, как работает valgrind, который реализует всю виртуальную машину, чтобы отслеживать адреса и ссылки на память и связанную с ними учетную запись. Подход valgrind намного дороже, но также намного эффективнее, поскольку он также может рассказать вам о других типах ошибок памяти, например, за пределами чтения или записи.
Valgrind по существу использует основные инструкции и может отслеживать, когда на заданный адрес памяти больше нет ссылок. Он может сделать это, отслеживая назначения адресов, и поэтому он может сказать вам не только, что часть памяти была потеряна, но и когда она потерялась.
С++ делает вещи немного сложнее для обоих типов детекторов утечки, поскольку он добавляет операторы new
и delete
. Технически new
может быть совершенно другим источником памяти, чем malloc
. Однако на практике многие реальные реализации С++ используют malloc
для реализации new
или имеют возможность использовать malloc
вместо альтернативного подхода.
Также языки более высокого уровня, такие как С++, имеют альтернативные способы более высокого уровня выделения памяти типа std::vector
или std::list
. Базовый детектор утечек сообщал о потенциально многих распределениях, выполняемых режимами более высокого уровня отдельно. Это гораздо менее полезно, чем говорить, что весь контейнер был потерян.
Ответ 2
Здесь опубликован технический документ о том, как работает наш инструмент CheckPointer.
В основном он отслеживает время жизни всех значений (куча и стек) и их размеры в соответствии с их типами, определяемыми языком. Это позволяет CheckPointer находить не только утечки, но и связанные с доступом к массиву, даже для массивов в стеке, которые valgrind не будет делать.
В частности, он анализирует исходный код, чтобы найти все используемые указатели. (Это сама задача сама по себе).
Он отслеживает метаданные указателя для каждого указателя, состоящего из
- Ссылка на метаданные объекта для объекта, выделенного кучей, или глобальной или локальной переменной или функции, на которую указывает указатель, и
- Диапазон адресов объекта (суб) объекта, к которому в данный момент может обращаться указатель. Это может быть меньше, чем диапазон адресов весь объект; например если вы берете адрес члена структуры, исходный код инструментального обеспечения будет разрешать доступ только к этому члену при использовании полученного указателя.
Он также отслеживает вид и местоположение каждого объекта, то есть это функция, глобальная, нить-локальная или локальная переменная, память, выделенная кучей, или константа строкового литерала:
- Диапазон адресов объекта, к которому можно безопасно получить доступ, и
- Для каждого указателя, хранящегося в выделенном кучей объекте или переменной, ссылка на метаданные указателя для этого указателя.
Все это отслеживание выполняется путем преобразования исходного источника программы в программу, которая выполняет то, что делает оригинальная программа, и чередует различные процедуры проверки или обновления метаданных. Полученная программа компилируется и запускается. Когда проверка метаданных не выполняется во время выполнения, backtrace предоставляется отчет о типе сбоя (недопустимый указатель, указатель за пределами допустимых границ,...)
Ответ 3
Это помечено как C, так и С++, и никакой операционной системы не упоминается. Этот ответ предназначен для Windows.
С
В Windows есть концепция виртуальной памяти. Любая память, которую может получить процесс, - это виртуальная память. Это делается через VirtualAlloc() [MSDN]. Вы можете представить детектор утечки, чтобы поставить точку останова на эту функцию, и всякий раз, когда он вызывается, он получает столбец и сохраняет его где-то. Тогда он может сделать подобное для VirtualFree() [MSDN].
Затем можно идентифицировать и показать разницу вместе с стоп-кодами, которые были сохранены.
С++
С++ имеет другую концепцию: он принимает большие 64kb-блоки, которые он получает от VirtualAlloc(), и разбивает их на более мелкие куски, называемые кучей. Менеджер кучи С++ поставляется с Microsoft и предлагает новые методы HeapAlloc() [MSDN] и HeapFree() [MSDN].
Затем вы можете сделать то же самое, что и раньше, но на самом деле эта функция уже встроена. Microsoft Инструмент GFlags [MSDN] может включить отслеживание:
В этом случае он будет сохранять до 50 МБ информации о вызовах для вызовов диспетчера кучи С++.
Поскольку эти настройки также могут быть активированы через реестр Windows, детектор утечки памяти может легко использовать его.
Общая концепция
Как вы можете видеть, общая концепция состоит в том, чтобы отслеживать распределения и освобождения, сравнивать их и показывать вызовы разницы.