Описание тега memory-management

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

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

Управление памятью обычно происходит на двух разных уровнях:

  1. Управление виртуальной памятью
    Ядро операционной системы управляет страницами физической памяти и отображает их в виртуальные адресные пространства процессов по их запросу.

    Следующие методы / алгоритмы попадают в категорию управления виртуальной памятью:

    • Разбиение по страницам: процесс записи содержимого неиспользуемых страниц на диск с целью повторного использования страницы RAM для других целей (выход страницы). Когда данные снова требуются, оборудование выдает прерывание из-за неотображенного адреса памяти, которое ядро ​​разрешает, считывая страницу с диска. Хотя разбиение на страницы полностью прозрачно для процессов пользовательского пространства, оно может серьезно замедлить работу системы.

    • CoW (Копирование при записи): Хорошие реализации fork()системный вызов не будет копировать все данные процесса. Вместо этого копируются только таблицы страниц, а все страницы памяти помечаются как доступные только для чтения. Каждый раз, когда происходит нарушение прав доступа из-за того, что один из разветвленных процессов пытается выполнить запись на страницу памяти, ядро ​​просто копирует содержимое этой страницы.

    • Файлы с отображением памяти: страницы памяти не обязательно должны поддерживаться областью подкачки, они также могут поддерживаться файлами. Такие файлы с отображением памяти обычно можно выгружать без записи чего-либо на диск, потому что отображение памяти обычно используется как средство ввода, а не вывода. Например, разделы кода из исполняемых файлов и библиотек обычно отображаются в памяти, что позволяет избежать дублирования данных в памяти, когда несколько процессов используют один и тот же исполняемый файл / библиотеки. Отображение памяти также доступно для процессов пользовательского пространства черезmmap() системный вызов.

  2. Динамическое управление памятью

    Этот второй уровень управления памятью является локальным для каждого процесса и обычно реализуется стандартной библиотекой C (malloc(), realloc(), а также free()). В качестве второго уровня управления памятьюmalloc() полагается на brk() а также mmap()системные вызовы для запроса страниц памяти у ядра. Крупные ассигнования обычно напрямую удовлетворяютсяmmap()вызов. Для небольших ассигнованийmalloc() реализации отслеживают отображаемую неиспользуемую память, разделяя неиспользуемую память по мере необходимости для соответствия запросам от пользовательского кода и запрашивая новые страницы памяти у ядра всякий раз, когда не обнаруживается подходящего свободного блока памяти.

    Общие цели для динамических распределителей памяти:

    • Безопасность потоков

    • Без ненужной фрагментации памяти

    • Низкий объем памяти, используемый для бухгалтерских целей

    • Низкие задержки выделения / освобождения

      Это включает оптимизацию поиска подходящих свободных блоков и методы уменьшения количества системных вызовов.

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

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

    Несмотря на то, что ядро ​​не отвечает за управление динамической памятью для процессов, оно все равно должно делать это для себя, в LINUX это выполняется kmalloc()функция. Кроме того, потокам ядра нужны собственные стеки. В отличие от диспетчеров динамической памяти пользовательского пространства, средства ядра не могут полагаться на диспетчер виртуальной памяти.

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

  • Явное управление: пользователь должен позаботиться о том, чтобы каждый вызов выделения соответствовал вызову освобождения.

  • Подсчет ссылок: некоторые объекты отслеживают, сколько раз происходит обращение к каждому блоку памяти. Счетчик ссылок может находиться в самом блоке памяти или где-то за его пределами. Важной реализацией этого являетсяstd::shared_ptr<> в C++.

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

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