Когда в последний раз Вы задумывались, как выделяется память на самом низком уровне? Пытались ли Вы изобрести этот «велосипед» с нуля? Простой ли это «велосипед»?

В данной серии публикаций я постараюсь рассказать про выделение памяти в операционной системе Linux 6-й версии ядра с картинками и источниками, а также рассказать про особенности ее работы со стандартной библиотекой C. Целью данной серии публикаций является выявление связи вызова malloc, структур ядра, системных вызовов и выделений физических страниц процессам.

Ну что, пошлите смотреть, из чего сделан «велосипед» памяти?

Основная часть

Начнем с главного: структур ядра, системных вызовов Linux и виртуального адресного пространства. Сначала немного слов про физическую память и виртуальную. Ядра операционных систем управляют именно физической памятью, когда процессам выдается так называемое «виртуальное адресное пространство». Память, не важно какая, формируется в страницы, размер которых в нынешних версиях ОС равен 4096 байт или просто 4 КБ.

Процессы и память

В дескрипторе процесса task_struct имеется указатель mm. Процессы, обладающие адресным пространством, содержат указатель mm не равный NULL.

Часть листинга структуры task_struct:

 struct task_struct {
 ...
         struct mm_struct		mm;
         struct mm_struct		active_mm;
         struct address_space		*faults_disabled_mapping;
         int				exit_state;
         int				exit_code;
         int				exit_signal;
 ...
 };

Адресные пространства процессов определяются структурой mm_struct. Это означает, что для каждого процесса существует только один её экземпляр, который разделяется между пользовательскими потоками. Немного про mm_struct:

struct mm_struct {
        struct vm_area_struct  *mmap;               /* list of memory areas */
        struct rb_root         mm_rb;               /* red-black tree of VMAs */
        struct vm_area_struct  *mmap_cache;         /* last used memory area */
        unsigned long          free_area_cache;     /* 1st address space hole */
        pgd_t                  *pgd;                /* page global directory */
        atomic_t               mm_users;            /* address space users */
        atomic_t               mm_count;            /* primary usage counter */
        int                    map_count;           /* number of memory areas */
        struct rw_semaphore    mmap_sem;            /* memory area semaphore */
        spinlock_t             page_table_lock;     /* page table lock */
        struct list_head       mmlist;              /* list of all mm_structs */
        unsigned long          start_code;          /* start address of code */
        unsigned long          end_code;            /* final address of code */
        unsigned long          start_data;          /* start address of data */
        unsigned long          end_data;            /* final address of data */
        unsigned long          start_brk;           /* start address of heap */
        unsigned long          brk;                 /* final address of heap */
        unsigned long          start_stack;         /* start address of stack */
        unsigned long          arg_start;           /* start of arguments */
        unsigned long          arg_end;             /* end of arguments */
        unsigned long          env_start;           /* start of environment */
        unsigned long          env_end;             /* end of environment */
        unsigned long          rss;                 /* pages allocated */
        unsigned long          total_vm;            /* total number of pages */
        unsigned long          locked_vm;           /* number of locked pages */
        unsigned long          def_flags;           /* default access flags */
        unsigned long          cpu_vm_mask;         /* lazy TLB switch mask */
        unsigned long          swap_address;        /* last scanned address */
        unsigned               dumpable:1;          /* can this mm core dump? */
        int                    used_hugetlb;        /* used hugetlb pages? */
        mm_context_t           context;             /* arch-specific data */
        int                    core_waiters;        /* thread core dump waiters */
        struct completion      *core_startup_done;  /* core start completion */
        struct completion      core_done;           /* core end completion */
        rwlock_t               ioctx_list_lock;     /* AIO I/O list lock */
        struct kioctx          *ioctx_list;         /* AIO I/O list */
        struct kioctx          default_kioctx;      /* AIO default I/O context */
};

Современные 64 разрядные системы на операционной системе Linux обеспечивают адресное пространство размером в 256 терабайт, используя 48 битную адресацию. Так как каждый процесс имеет свое виртуальное адресное пространство, то его размер также составляет 256 терабайт. На рисунке ниже показано адресное пространство процесса. Процесс может адресовать адреса до 0x0000 7FFF FFFF F000, что обеспечивает адресацию 128ТБ. Регион памяти 0x0000 7FFF FFFF F000-0xFFFF FFFF FFFF FFFF используется операционной системой и имеет адресуемый размер в 128ТБ.

Адресное пространство процесса
Адресное пространство процесса

В адресном пространстве процесса задействованы отдельные регионы. Полностью адресное пространство редко используется. Каждый регион выделен структурой vm_area_struct, которые никогда не перекрываются и представляют собой последовательность адресов с одинаковой защитой и назначением. Регион адресного пространства определяется границами в виртуальном адресном пространстве. Границы региона памяти представлены двумя полями в структуре vm_area_struct: vm_start и vm_end. На рисунке ниже показан классический пример границ региона виртуального адресного пространства. Регион может быть представлен в виде разделяемой библиотеки, некоторой области кучи, коду, сегменту данных, отображенному файлу. Так как регион виртуальный, то одна его часть может быть загружена в память, а другая - нет. Если регион памяти связан с файлом, то поле vm_file не равно NULL.

Представление структур vm_area_struct в адресном пространстве процесса
Представление структур vm_area_struct в адресном пространстве процесса

Структура vm_area_struct:

struct vm_area_struct {
        struct mm_struct             *vm_mm;        /* associated mm_struct */
        unsigned long                vm_start;      /* VMA start, inclusive */
        unsigned long                vm_end;        /* VMA end , exclusive */
        struct vm_area_struct        *vm_next;      /* list of VMA's */
        pgprot_t                     vm_page_prot;  /* access permissions */
        unsigned long                vm_flags;      /* flags */
        struct rb_node               vm_rb;         /* VMA's node in the tree */
        union {         /* links to address_space->i_mmap or i_mmap_nonlinear */
                struct {
                        struct list_head        list;
                        void                    *parent;
                        struct vm_area_struct   *head;
                } vm_set;
                struct prio_tree_node prio_tree_node;
        } shared;
        struct list_head             anon_vma_node;     /* anon_vma entry */
        struct anon_vma              *anon_vma;         /* anonymous VMA object */
        struct vm_operations_struct  *vm_ops;           /* associated ops */
        unsigned long                vm_pgoff;          /* offset within file */
        struct file                  *vm_file;          /* mapped file, if any */
        void                         *vm_private_data;  /* private data */
};

На рисунке ниже показана связь структур mm_struct и vm_area_struct. В mm_struct указатель mmap указывает на первый vm_area_struct в виртуальном адресном пространстве. Структуры vm_area_struct составляют односвязный список в каждой mm_struct. Каждое vm_area_struct имеет указатель на mm_struct через поле vm_next.

Связь структур mm_struct и vm_area_struct
Связь структур mm_struct и vm_area_struct

На рисунке ниже представлена связь структуры vm_area_struct и file. Если указатель vm_file не равен NULL, то vm_area_struct связана с файлом.

Связь структур vm_area_struct и file
Связь структур vm_area_struct и file

Теперь к маленьким выводам и дополнениям.

Разрядность системы — это разрядность ЦПУ. Все современные ЦПУ используют 64 бита для вычислений, когда достаточно древние ЦПУ используют 32 бита. Если уж говорить и про 16-ти битные ЦПУ, то рассматриваются ЦПУ 20-го века. Эти биты позволяют использовать 2^{64}значений. Так как указатель — это переменная, по объему разрядности которая 64 бита, 8 байт, то и указывает она на 2^{64} байт. В ОС Linux используется 48 бит для адресации в виртуальном адресном пространстве.

Теперь про разницу виртуальной и физической памяти. С точки зрения ядра (НЕ цитировать!) вся физическая память — одно единое адресное пространство. То есть ядро видит все, что лежит в каждой плашке ОЗУ. Виртуальное адресное пространство на то и виртуальное, что на самом деле не является действительным. Оно выдается каждому процессу, чтобы процесс считал, что у него находится ВСЯ память вычислительной системы. Действительно используется лишь малая часть этого пространства. Каждая страница такого адресного пространства называется виртуальной. Особенностью виртуальной страницы относительно изучаемой темы является ее резидентность. Резидентная страница — это виртуальная страница, которая выгружена в физическую память, то есть находится таблице страниц. Причем все виртуальные страницы при выделении остаются выгруженными (не в оперативной памяти) до тех пор, пока к ним не произойдет обращение, что вызовет страничное прерывание.

Виртуальное адресное пространство процесса есть структура mm_struct, которая в себе имеет используемые регионы виртуального адресного пространства, именуемых vm_area_struct и образующих односвязный список.

Последний важный вывод: процесс не обладает памятью. Процесс имеет виртуальное адресное пространство.

Анализ системных вызовов brk и mmap

Можно спросить себя: как тогда выделяется память обычным процессам? На этот вопрос отвечают два системных вызова: brk и mmap.

Системные вызовы brk и mmap/munmap предназначены для управления регионами в виртуальном адресном пространстве.

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

Системные вызовы mmap и munmap нужны для управления отображениями в виртуальном адресном пространстве процесса. При вызове mmap создается новый vm_area_struct для одного отображения. Системный вызов munmap используется для удаления vm_area_struct. При вызове mmap возвращает указатель на отображенные данные. Поддерживается флаг MAP_ANONYMOUS, позволяющий реализовывать анонимные отображения. Анонимное отображение --- это отображение пространства виртуальной памяти процесса, а не файла в пространстве файловой системы. Анонимные отображения не являются частью стандарта POSIX, однако реализованы во многих системах

Оба системных вызова полагаются на механизм отложенного физических страниц (demand paging) ядра. Виртуальные страницы выделяются немедленно, но физические страницы памяти выделяется только тогда, когда при операции чтения/записи случается страничное прерывание.

Также оба системных вызова не могут выделять «случайное» количество памяти. Они «округляют» запрос до ближайшей страницы.

Теперь переварим сказанное. Системный вызов brk используется для изменения границы особой vm_area_struct. При чем эта vm_area_struct связана с кучей процесса (Heap) и изменяется именно граница, связанная с названием "разрыв программы" (program BReaK, отсюда и название системного вызова brk). Системный вызов mmap создает совершенно новый vm_area_struct в виртуальном адресном пространстве, то есть ничего не расширяет, а создает новый регион памяти.

Виртуальная память также выделяется страницами, как и физическая память.

Другой важный вывод заключается в выделении памяти. Виртуальная память выделяется МОМЕНТАЛЬНО при вызове. Виртуальная страница памяти будет загружена в физическую память только при первом обращении к ней.

Заключение

В данной серии публикации мы рассмотрели каркас нашего «велосипеда». Однако до сих пор мы не ответили на вопросы «что делать с системными вызовами?». В следующей серии публикаций будем рассматривать механизмы управления памятью в виртуальном адресном пространстве. Рассмотрим часть реализации библиотеки Glibc и ее аллокатора ptmalloc2.

Источники

Комментарии (26)


  1. unreal_undead2
    12.12.2025 11:55

    Хотелось бы услышать побольше про маппинг виртуальной памяти на физическую - как структуры ядра ОС отображаются на таблицы страниц процессора, в какие моменты происходят изменения и дорогие действия (скажем, инвалидация TLB).


    1. Tsar_Drobovik Автор
      12.12.2025 11:55

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


      1. zVlad909
        12.12.2025 11:55

        А как вооще можно было бы описать работу виртуальной памяти без введения в эти самые "многоуровневые таблицы " и MMU (если не ошибаюсь).

        У Вас получилась телега впереди лошади.


        1. Tsar_Drobovik Автор
          12.12.2025 11:55

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

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

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

          Надеюсь, вы поняли мою точку зрения и почему я решил это не вводить в курс дела.


          1. zVlad909
            12.12.2025 11:55

            Надеюсь, вы поняли мою точку зрения и почему я решил это не вводить в курс дела.

            Честно говоря нет, не понял. Я много раз читал и слушал про механизм виртуальной памяти на разных платформах, начиная с ИБМ МФ и БЭСМ-6, и всегда эти рассказы во первых же строках раскрывали смысл "черной коробочки", или DAT в случае с ИБМ МФ:

            An IBM Mainframe DAT (Dynamic Address Translation) refers to the core hardware/software process that translates virtual memory addresses into physical ones, ...

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

            В БЭСМ-6 виртуальная память устранена иначе.


  1. Urub
    12.12.2025 11:55

    Ну хоть какаято польза от подорожания памяти - пошли статьи как с ней правильно работать


    1. Tsar_Drobovik Автор
      12.12.2025 11:55

      В следующей серии будет рассказано про механизм управления памятью в виртуальном адресном пространстве процесса, то есть про стандартную библиотеку Glibc. Это Вызовы malloc, calloc и realloc. Если объема не хватит, сразу приведу особенности работы с физической памятью (сколько выделяется, когда и почему).


  1. LinkToOS
    12.12.2025 11:55

    Теперь про разницу виртуальной и физической памяти.

    Странное описание разницы между типами памяти. Они все физические.
    Есть RAM - оперативная память, с прямой двоичной адресацией. Каждому двоичному адресу на шине процессора, прямо соответствует ячейка памяти в RAM.
    Есть виртуальная память на диске, которая организована как файл в файловой системе. Нельзя просто выставить на шине процессора адрес в области виртуальной памяти, и считать содержимое. Это делается через посредника, который преобразует двоичный адрес ячейки памяти, к которой обращается приложение, в позицию элемента в файле на диске.


    1. unreal_undead2
      12.12.2025 11:55

      Сразу после аллокации (скажем, анонимным mmap'ом) кусок памяти только виртуальный - ему не соответствуют никакие данные ни в RAM ни на диске. Только после первого обращения при обработке исключения процессора будут выделяться физические страницы, которые позже могут переехать на диск.


    1. Tsar_Drobovik Автор
      12.12.2025 11:55

      Виртуальная память не обязана быть на диске, возможно, Вы немного неправильно поняли. Скажем, что мы выделили память каким-нибудь системным вызовом и получили указатель. Этот указатель ВСЕГДА будет указывать на адрес в виртуальном адресном пространстве, что как раз и описывается структурой mm_struct в ядре. Эта память по умолчанию не в оперативной памяти. Виртуальные страницы связываются с физическими через таблицу страниц, что в одном и комментариев выше посоветовали рассмотреть. Это означает, что такой адрес при обращении будет адресовать линейно физическую память. Про сущность виртуальных страниц могу добавить еще немного про тот факт, что если она не в памяти, то они либо никогда в нее не загружались (и при обращении случится minor page fault), либо когда-то были вытеснены на диск (и при обращении случится major page fault).


      1. zVlad909
        12.12.2025 11:55

        Я согласен с @LinkToOSчто описание связи виртуальной памяти с реальной (или ели хотите физической, но когда я много лет назад изучал архитектуры ЭВМ это называлось реальной памятью, хотя да в лексиконе плятформы х86 используется термин physical memory) в статье довольно запутано ("странно" у @LinkToOS. .

        Вот первое что дает Гугл по поводу объяснения виртуальной памяти в ОС MVS (это понятное дело мэйнфрэйм система. Схожие описания имеются и для других платформ и ОС):

        Виртуальная память — это концепция операционной системы мэйнфреймов IBM, в которой каждая задача получает собственное большое, личное адресное пространство, используя страничную организацию памяти для отображения виртуальных адресов на реальную память (ОЗУ) и диск (вспомогательное хранилище), что позволяет создавать масштабные программы, эффективно выполнять многозадачные операции и защищать память.

        Ключевые концепции

        Несколько адресных пространств: Вместо одной общей памяти MVS предоставляет каждой программе (задаче/заданию) собственное большое, изолированное виртуальное адресное пространство.

        Отображение виртуальных адресов в реальные: Аппаратное обеспечение (блок управления памятью) преобразует виртуальные адреса, используемые программами, в физические адреса в ОЗУ или на диске с помощью таблиц страниц.

        Подкачка/страничная адресация: MVS перемещает блоки памяти (страницы) между быстрым центральным хранилищем (ОЗУ) и более медленным вспомогательным хранилищем (диском) по мере необходимости, обрабатывая ошибки страничного доступа, когда программе требуется страница, отсутствующая в ОЗУ.

        Аналогичное упоминает об аппартном обеспечении есть и в описании виртуальной памяти в PDP-11 (полагаю и на других платформах тоже):

        •  MMU (Memory Management Unit): Hardware added to later PDP-11s (like the 11/70) to translate virtual addresses to physical ones, supporting segmentation and paging.

        У автора отсутствует упоминание (поправьте если это не так) аппартной поддержики виртуальной памяти т.е. динамической трансляции виртуальных адресов в реальные (физические). Это важно для понимания виртуальной памяти и как она функционирует. Объяснять это через "разницу виртуальной и физической памяти"

        Автор упоминает некую "таблицу страниц", но как и чем она используется не раскрывает. Нет и упоминания о сегментах имеющих место быть на х86 тоже.

        Разрядность системы — это разрядность ЦПУ. Все современные ЦПУ используют 64 бита для вычислений, ....... Эти биты позволяют использовать 2^{64}значений. Так как указатель — это переменная, по объему разрядности которая 64 бита, 8 байт, то и указывает она на 2^{64} байт. В ОС Linux используется 48 бит для адресации в виртуальном адресном пространстве.

        Инистинктивно хочется спросить: "Почему и как только 48 бит?". В статье на это ответа нет. Потому что нет описания аппаратной поддержки виртуальной памяти и роли "таблицы страниц".

        Что еще важно учесть рассказывая про витуальную память это различие механизмов виртуализации памяти в Операцианных Системах и Виртуальных Машинах. Да они базуруются на одних и тех же принципах работы компьютера, но в случае ВМ это "чистая" виртуальная память от нуля до бесконечности (или до значения заданого конфигурацией ВМ), а в ОС (реальной машины или виртуальной) есть прослойка супервизора ОС, у которого процесс запрашивает память инкрементально по мере надобности, в рамках которых программа обязуется выполняться и только баг программы может обратиться во вне инкремета(ов), и только стартовый код процесса загружается в память созданой супервизором ОС. Другими словами ОС ведет учет и отслеживает все запросы прикладного процесса на память. Выход за пределы этих запросов означает аварийное завершение процесса. Гипервизор же ВМ позволяет использовать виртуальную память ВМ как угодно, полагаясь на ОС ВМ в рамках ее принципов управления процессами/программами.

        В целом статья даже для меня, ИТ-шника с более чем 40 летним стажем и именно в области систем, выглядит не убедительно, малоинформативно и даже запутано. Вот примеры из статьи:

        Последний важный вывод: процесс не обладает памятью. Процесс имеет виртуальное адресное пространство.

        .....

        Виртуальная память также выделяется страницами, как и физическая память.

        Другой важный вывод заключается в выделении памяти. Виртуальная память выделяется МОМЕНТАЛЬНО при вызове. Виртуальная страница памяти будет загружена в физическую память только при первом обращении к ней.

        Начал читать статью чтобы понять как работает с памятью Линукс на х86 и ничего кроме ссылок на структуры Линукс с туманными описаниями их значения и использования ядром Линукс не нашел. Нет этого в статье. При этом, хоть это и было давно, я изучал архитектуру Интел процессора и помню что там были сегменты и вообще есть четыре метода управления виртуальной памятью лишь одно из которых используется Windows и Linux. А хотелось бы узнать почему именно одно и что с остальными.


        1. Tsar_Drobovik Автор
          12.12.2025 11:55

          Спасибо за развернутую критику!

          Да, в моей работе не рассматриваются сегменты адресного пространства процесса в деталях, однако просто упоминаются в рисунке "Адресное пространство процесса".

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


          1. zVlad909
            12.12.2025 11:55

            Я сразу понял что Вы будете в основном рассказывать как Линукс управляет памятью процессов. Но это управление в принципе может иметь место и без виртуализации памяти. И в самом деле в первых ОС процесса разделяли физическую память, и ей управлял супервизор ОС без виртуализации памяти.

            Потом появились системы где виртуальная память "была" только у супервизора ОС, а процессы видели свои регионы.

            В современных системах каждый процесс имеет свою виртуальную память. (Честно говоря пока не уверен что это про Линукс, но надеюсь что да)

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

            И вообще управление памятью процессов в Линукс и виртуальная память это две практически разные (независимые) темы. Рассказывать сразу про них методически не корректно, особенно для новичков.

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

            A Translation Lookaside Buffer (TLB) is a high-speed cache within a processor's Memory Management Unit (MMU) that stores recent translations of virtual memory addresses to physical memory addresses, acting as an address-translation cache to speed up memory access by avoiding slow page table lookups in main memory. When the CPU needs a memory location, it first checks the TLB (a TLB Hit); if found, the physical address is quickly provided, but if not (a TLB Miss), the system must consult the page tables, which is slower, requiring hardware or OS intervention. TLBs are crucial for performance, as they reduce multiple memory accesses to potentially just one, using locality of reference to cache frequently used mappings. 

            How it Works

            • Virtual to Physical: The TLB maps a Virtual Page Number (VPN) to a Physical Page Frame.

            • Lookup: A virtual address is broken down; the MMU uses the VPN to check the TLB.

            • Hit: If the translation is in the TLB, the physical address is returned instantly, saving significant time.

            • Miss: If not, the page table in main memory is accessed (often involving multiple memory reads), and the new translation is added to the TLB, potentially evicting an old entry. 

            Мне честно говоря это не очень это описание нравится потому что здесь тоже смешаны котлеты и мухи. Т.е. трансляция виртуальных адресов в физические и хранение TLB в кэше что есть тема производительности (я это выделил выше), а не принципа виртуализации памяти как такового. В итоге суть оказывается затумаененной. .

            Но взял этот пример потому что он не из ИБМ мэйнфрэйм документации чтобы лишний раз не раздражать читателей неадекватно относящихся к теме ИБМ МФ. Таких здесь много.


      1. zVlad909
        12.12.2025 11:55

        Скажем, что мы выделили память каким-нибудь системным вызовом и получили указатель. Этот указатель ВСЕГДА будет указывать на адрес в виртуальном адресном пространстве, что как раз и описывается структурой mm_struct в ядре. Эта память по умолчанию не в оперативной памяти. 

        А не должне ли после этого произойти считывание кода процесса с файла на диске по этому "указателю" в физической памяти и передачи управления точке входа в процесс?

        Правильно ли я понял что в этом случае под "оперативной памятью" Вы имеете в виду "физическую память"?


        1. Tsar_Drobovik Автор
          12.12.2025 11:55

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


          1. zVlad909
            12.12.2025 11:55

            Минуточку. Давайте всё же рассмотрим как и в чем материализуется/загружается код процесс. Вы говорите что "....страницы с кодом загружаются как и все остальные - только при страничном прерывании."

            Вопрос: Что и как инициирует первоначальную загрузку кода процесса в память?

            Сам процесс понятное дело сделать это не может - его еще нет. Код процесса находится в файле на диске. Система? Без оборащения к файлу с кодом процесса на диске? А ведь для того и начинается срздание адресного пространства чтобы в него поместить код из файла на диске. Причем не из файла страничного обмену куда попадают страницы процессов в результате вытеснения.

            Поправьте или продолжите эту мою логику.


    1. zVlad909
      12.12.2025 11:55

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

      Ах да, Вы говорите "через посредника". Что это за такой замечательный посредник?


      1. LinkToOS
        12.12.2025 11:55

        Посредник - это менеджер памяти.

        в физическую память

        Все-таки в оперативную память. Дисковая подсистема памяти тоже физическая. Любая память физическая. А разделение на "физические" и "виртуальные" относится к адресам.

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

        Запись на дисках по блокам. Поэтому без кеша в оперативной памяти обойтись не получится.

        Хотя теоретически, можно было бы сделать аппаратную поддержку, вовлечь контролер диска в процедуру отображения, и резервировать на диске место в специальном формате.


        1. zVlad909
          12.12.2025 11:55

          Интересно ы Вас получается. Вообщем то мне известно что в теории микропроцессоров (а точнее архитектуры "общая шина") внешние устройства представляются как участок памяти (ОЗУ). Но это лишь для драйверов этих устройств и как буфер обмена данными. Когда же мы говорим о коде программы, выполняемой не как драйвер устройства, мы должны разделять физическое ОЗУ и физичекие файлы на внешних устройствах. Другими словами команды ЦПУ, иные чем команды ввода-вывода не могут напрямую адркссовать блоки данных на дисках. Это имеено то что имеет отношения к обсуждаемой здесь "виртуальной памяти". Собственно и Вы об этом сказали, говоря: "Поэтому без кеша в оперативной памяти обойтись не получится."

          Хотя теоретически, можно было бы сделать аппаратную поддержку, вовлечь контролер диска в процедуру отображения, и резервировать на диске место в специальном формате. ....

          Почему теоритически? Это есть в каждой современной системе. Это и есть часть работы с виртуальной памятью. В каждой системе есть "место на диске" (Page file) куда система сбрасывает/вытесняет содержимое страниц ОЗУ с целью их освобождения для содержимого страниц ранее вытесненых в этот файл, но востребованных процессом. А как иначе? Ведь сумма размеров материализованных адресных пространств всех процессов как правило превышает размер ОЗУ (физической памяти). .


          1. LinkToOS
            12.12.2025 11:55

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

            Виртуальным адресам памяти. Память всегда реальна, и существует в физическом виде.

            Я понимаю о чем вы говорите. Но все пишут по разному. Одни пишут "виртуальная память", другие "виртуальное адресное пространство".

            Почему теоретически? Это есть в каждой современной системе. Это и есть часть работы с виртуальной памятью.

            Это программные процедуры. Теоретически их можно сделать аппаратными.


            1. zVlad909
              12.12.2025 11:55

              Это программные процедуры. Теоретически их можно сделать аппаратными.

              На самом деле "виртуальная память" это программно-аппартная процедура. Преобразование виртуального адреса в физический (или реальный), в том случае когда страница виртуальной памяти находится в ОЗУ (это называется frame), выполняется аппаратными средствами (DAT) c использованием таблицы страниц, а когда страница не в ОЗУ, то включается программная процедура, по прерыванию отсутствия страницы от DAT, и программно эта страница загружается с диска (из Page file) в ОЗУ, затем модифицируется таблица страниц и выполнение команды повторяется.


  1. Gargoni
    12.12.2025 11:55

    ОС постоянно пробегает линейно список vm_area_struct?

    В какой момент и при каких обстоятельствах система отказывает в выделении виртуальной памяти процессу?


    1. Tsar_Drobovik Автор
      12.12.2025 11:55

      Виртуальную память можно выделять до тех пор, пока все виртуальное адресное пространство не будет занято регионами памяти. Однако это не совсем правда, потому что системным вызовам brk и mmap подлежат только некоторые регионы виртуального адресного пространства, а именно куча (для brk) и регион отображений, называемый memory-mapped region. Не все виртуальные страницы связаны с физическими. Ответ как связаны отвечу в следующих сериях, но если очень кратко сейчас - при первом обращении, что зарубежные источники называют demand paging.

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


  1. zVlad909
    12.12.2025 11:55

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

    A Translation Lookaside Buffer (TLB) is a high-speed cache within a processor's Memory Management Unit (MMU) that stores recent translations of virtual memory addresses to physical memory addresses, acting as an address-translation cache to speed up memory access by avoiding slow page table lookups in main memory. When the CPU needs a memory location, it first checks the TLB (a TLB Hit); if found, the physical address is quickly provided, but if not (a TLB Miss), the system must consult the page tables, which is slower, requiring hardware or OS intervention. TLBs are crucial for performance, as they reduce multiple memory accesses to potentially just one, using locality of reference to cache frequently used mappings. 

    How it Works

    • Virtual to Physical: The TLB maps a Virtual Page Number (VPN) to a Physical Page Frame.

    • Lookup: A virtual address is broken down; the MMU uses the VPN to check the TLB.

    • Hit: If the translation is in the TLB, the physical address is returned instantly, saving significant time.

    • Miss: If not, the page table in main memory is accessed (often involving multiple memory reads), and the new translation is added to the TLB, potentially evicting an old entry. 


    1. Tsar_Drobovik Автор
      12.12.2025 11:55

      Да, если мы бы рассматривали таблицы страниц и как виртуальная память действительно связана с физической. Данная работа (по крайней эта часть работы) посвящана исключительно рассмотрению структур ядра, системных вызовов и структур, которые в последствии будут связаны со стандартной библиотекой Glibc, вызовом malloc и особенностью загрузки страниц в физическую память.

      Возможно, под "особенностью работы с физической памятью" Вы желали увидеть связку MMU, TLB, Page tables, загрузка по надобности (demand paging), двоичный аллокатор "друзей" и, что уже написано, mm_struct и vm_area_struct. В следующих публикациях постараюсь ввести это понятие конкретнее.


      1. zVlad909
        12.12.2025 11:55

        Данная работа (по крайней эта часть работы) посвящана исключительно рассмотрению структур ядра, системных вызовов и структур, которые в последствии будут связаны со стандартной библиотекой Glibc, вызовом malloc 

        Вот с этого и надо было начинать, с malloc, и лишь потом вводить виртуальную память. Но Вы начаи именно с виртуальной памяти. И не до конца разобравшись с ней приступили к управлению памятью ядром Линукс. Получилось пока не то ни сё, ни рыба ни мясо.

        Жду следуших частей. Я брал курсы ИБМ по Линукс, но это было давно, так давно что уже практически ничего не помню, а конспекты лекций при очередном переезде непредусматрительно выбросил. Но тогда помню мне было всё просто и понятно. А сейчас ничего не понимаю из Вашей статьи.