1

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

Мой вопрос заключается в следующем: чтобы Windows (или вообще любая операционная система) знала, что память все еще зарезервирована после уничтожения указателя, используемого для управления этой памятью внутри приложения, она должна независимо отслеживать, какая память используется. Где это делается и как?

2 ответа2

2

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

Как правило, все операционные системы имеют подсистему управления памятью (или диспетчер памяти в Windows), которая отслеживает виртуальную память. Затем другая часть ОС, Hardware Abstraction, отображает эту виртуальную память на физические устройства. Это, конечно, запрещает прямое взаимодействие между любым пользовательским процессом и физической памятью.

Непосредственное взаимодействие с этой частью операционной системы частично доступно через общедоступный API - см. Функции управления памятью для Windows. В Linux есть несколько способов доступа к памяти, эта страница будет лучшим способом начать работу с ней.

1

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

Диспетчер памяти Windows (сокращенно Mm) отслеживает используемые виртуальные адреса с помощью набора структур данных, называемых дескрипторами виртуальных адресов. Для адресного пространства пользовательского режима это делается для каждого процесса отдельно. Когда процесс создается впервые, у него нет VAD. Когда часть виртуального адресного пространства переходит от свободного к несвободному - несвободный может быть зарезервирован, зафиксирован, отображен или один или два менее распространенных параметра - создается VAD. VAD содержит начальный адрес (всегда выровненный по страницам) и размер (также всегда выровненный по страницам) региона, тип распределения (зарезервированный, зафиксированный и т.д.) И некоторые другие вещи.

Область, описываемая VAD, может быть переопределена и / или подразделена. Например, для большого зарезервированного диапазона очень характерно, чтобы часть себя была изменена на "совершено". Это приводит к изменению исходного VAD для отражения новой длины зарезервированного региона и нового VAD, созданного для описания зафиксированного региона. Если зафиксированный регион выходит из "середины" диапазона, определенного исходным VAD, необходимо создать два новых VAD.

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

Из-за природы этого типа дерева эта операция очень эффективна как для поиска существующих VAD, так и для добавления и удаления VAD. для нахождения существующих VAD эффективен так же, как эффективен "бинарный поиск" в простом упорядоченном списке. Если, например, в дереве содержится от 31 до 64 VAD, для поиска любого заданного адреса необходимо просмотреть не более шести VAD. Для 65–128 VAD поиск занимает всего семь шагов и т.д. Но в отличие от простого упорядоченного списка, добавление или удаление записей не требует перестановки всех существующих.

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

Что касается "уничтожения указателя" - указатель - это просто место в памяти. Когда я выделяю виртуальную память (в Windows API низкоуровневый вызов для этого - VirtualAlloc), я получаю указатель на выделенную область. Перезапись указателя нулем или даже освобождение виртуальной памяти, в которой он хранится, не говорит ОС, что я сделал с регионом. В конце концов, я мог бы скопировать это значение указателя в другом месте. Что говорит ОС "Я закончил с этим регионом", так это вызов VirtualFree. Это удаляет VAD, который описал регион. Конечно, все виртуальное адресное пространство для процесса является атрибутом процесса, и все, что еще выделено, исчезает при удалении процесса (потому что все VAD тоже удаляются).

Связь между номерами виртуальных страниц и номерами физических страниц поддерживается в структурах, называемых таблицами страниц. Они также помогают в управлении виртуальным адресным пространством. Существует таблица страниц, состоящая из 512 записей таблицы страниц и занимающая одну страницу, на каждые 2 МБ виртуального адресного пространства; каждый PTE описывает одну страницу. СТ организованы в простую иерархическую структуру: три уровня в 32-битной x86, четыре уровня в x64. Таблицы страниц, соответствующие 2-мегабайтным пролетам vas, которые все свободны (то есть никакие VAD-ы не описывают что-либо в 2 МБ), фактически не существуют; таким образом, соответствующие записи в PT верхнего уровня равны нулю. Таблицы страниц также поддерживаются и обновляются диспетчером памяти ОС (а не "уровнем аппаратной абстракции", как утверждается в другом ответе).

(Предыдущий абзац предполагает PAE на x86. Без PAE это 1024 PTE на PT, и в дереве есть только два уровня PT.)

Еще один набор данных, "массив PFN", отслеживает состояние каждой физической страницы. Это простой массив структур, индексируемых по физическому номеру страницы ("номер фрейма страницы"). Каждый элемент массива содержит информацию о состоянии соответствующей физической страницы: на каком из общесистемных списков страниц он находится (свободный, резервный, обнуленный, измененный) или, если он находится в одном или нескольких рабочих наборах процессов, сколько процессов он выполняет в и т. д.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .