Физический адрес, прямая адресация, адресное пространство про-граммы. Сегментная адресация: сегменты, их назначение, виртуальный адрес, адресное преобразо-вание; виртуальная память: страничная адресация, страницы, страничное адресное преобразование и их использование при реализации виртуальной памяти; замещение страниц физической памяти, выделение страниц по мере необходимости.
При старте программы операционная система создаёт для нее специальный процесс. Можно сказать, что процесс является экземпляром программы, точнее - запущенным на компьютере экземпляром. Как уже упоминалось выше, одновременно на компьютере может быть запущено не-сколько экземпляров одной и той же программы, с чем Вы, наверняка, сталкивались - например, работая в Windows, легко запустить несколько экземпляров текстового редактора "Блокнот". Далее мы иногда будем использовать термины процесс и программа как сино-нимы считая, что из контекста понятно, о чём идёт речь.
В оперативную память созданного процесса копируется код соответствующей программы, а также выделяется память для данных программы. Процессор взаимодействует с этой памятью посредством адресов. Система адресации у современных компьютеров оказывается непростой, и мы начнём её изучать с понятия физического адреса.
Физический адрес (Physical Address) - это номер ячейки в оперативной памяти. Зная этот номер, процессор непосредственно обращается в нужное место оперативной памяти за необходимыми данными.
Когда мы говорим об адресуемой ячейке в оперативной памяти, то мы имеем в виду ма-шинное слово, которое, как рассказывалось в предыдущих лекциях, является минимально адресуе-мый фрагмент памяти.
Многие ЭВМ прошлых поколений, а также простые современные вычислительные уст-ройства с позволяют своим программам обращаться к оперативной памяти напрямую, по физическо-му адресу, минуя всевозможные адресные преобразования, о которых пойдёт речь в этой лекции. Такая организация работы с памятью называется прямой адресацией.
Прямая адресация - это механизм использования в ма-шинном коде программ реальных физических адресов в оперативной памяти, без использования ад-ресных преобразований.
Хотя данная схема, на первый взгляд, выглядит естественной, она не обладает достаточ-ной гибкостью - ведь в действительности не всё так просто! Поэтому в современных персональных компьютерах, смартфонах, планшетах и других сложных вычислительных устройствах прямая адресация не применяется. И нам есть о чём поговорить в рамках данной лекции.
Дадим теперь определения адресного пространства программы. Казалось бы, это - вся оперативная память, которая выделяется процессу. Однако это не так, поскольку программа может оперировать с оперативной памятью большего объёма, чем выделено её процессу. Для этого исполь-зуется механизм виртуальной памяти, о котором речь пойдёт чуть ниже. А тут мы дадим корректное определение адресного пространства программы
Адресное пространство (Address Space) - это множество адресов, допустимое для использования программой.
В частности, значения указателей в программах на языке C, работающих на компьютерах семейства процессоров Intel x86, являются элементами адресного про-странства.
Память, которая выделяется процессу при старте операционной системой, является набо-ром сегментов.
Сегмент - это фрагмент оперативной памяти, выделяе-мый операционной системой процессу.
Размер и конкретное расположение сегментов процесса операционная система выбирает, исходя из следующих параметров:
Рассмотрим классическую (упрощённую) схему памяти процесса, когда эта память состо-ит из сегмента кода, сегмента данных и сегмента стека. Адреса внутри сегментов формируются как смещения относительно начала сегмента. Код программы знает о сегментах и оперирует этими сме-щениями. Например, в операции сложения вида регистр/память адрес в памяти для второго операнда указывается в виде смещения от начала сегмента данных (напомним, что именно там хранятся все переменные программы). Таким образом, реальный физический адрес, по которому должен обратиться процессор, вычисляются уже внутри процессора, а последний в свою очередь, знает физические адреса начала каждого сегмента. Итак, мы подошли к понятию виртуального адреса и адресного преобразования.
Адрес, с которым непосредственно работает программа, называет-ся виртуальным адресом (Virtual Address).
Адресное преобразование (Address Conversion) - это ме-ханизм вычисления физического адреса по виртуальному.
Отметим, что сегментная организация памяти процесса является не единственным источ-ником виртуальных адресов.
Рассмотрим теперь подробнее сегменты процесса.
Сегмент кода хранит в оперативной памяти машинный код про-граммы.
Сегмент данных хранит глобальные переменные программы (так называемые статические данные), а также используется для кучи (heap) в том случае, если в программе используются динамические данные. Размер всего сегмента данных известен во время запуска программы, но память для кучи выделяется в нём по мере исполнения программы, поскольку на мо-мент запуска не понятно, сколько программе понадобится динамической памяти - это зависит от конкретного сценария исполнения программы, поскольку динамическая память запрашивается с уровня прикладной программы, и её использование организует сам программист - автор програм-мы. Соответственно, куча является "динамическим пузырём" нефиксированного размера, "раздувающийся" по мере запросов программы.
В программах на языке C для того, чтобы запросить динамическую память, программист использует функцию malloc, а в C++ - оператор new. Поскольку динамическая память выделяется "в ручном" режиме, то и освобождаться она должна также "вручную", с помощью специальных функций (функция free в С, оператор delete в C++). Меха-низм динамической памяти требует от программиста внимательности и организованности, но взамен предоставляет гибкость и возможность создавать более эффективные программы. Однако при использовании этого механизма программист может допустить (и допускает!) сложно обнаружимые ошибки. Это стало причиной того, что в современных промышленных языках, таких как Java, C#, Python использование динамической памяти доступно только через выделение объектов, а не массивов байтов, как в C, а освобождение - посредством автоматической сборки мусора, освобождающей память объектов, на которые больше нет ссылок из программы.
Сегмент стека используется процессом для организации вызо-вов процедур (методов) программы. Он реализует структуру данных под названием стек.
Набор небольших однотипных фрагментов памяти, объединённых в список, в котором новый элемент всегда добавляется только в конец списка, и удаляться из этого списка может также с конца, называется стеком.
В тот момент, когда в программе выполняется вызов очередной процедуры, в сегмент стека помещаются следующие данные:
Совокупность перечисленных данных образует так называемый кадр стека (stack frame). Очевидно, что после завершения процедуры и продолже-ния выполнения программы в том контексте, откуда процедура была вызвана, ни ее локальные дан-ные, ни параметры больше не нужны. Поэтому кадр завершённой процедуры удаляется со стека, ос-вобождая место для других данных. Если процедура вызывается рекурсивно, то её кадры с различ-ными значениями параметров, данных, адреса возврата размещаются на стеке столько раз, сколько раз она была вызвана. Если программа зацикливается на рекурсивном вызове, то она помещает на стек всё больше и больше данных, заполняя всю допустимую для стека память, и после этого ава-рийно завершается с ошибкой "переполнение стека" (Stack Overflow). Эта ошибка настолько известна и распространена, что в честь неё названа самая популярная платформа вопросов-ответов по программированию StackOverflow ().
Сделаем следующую ремарку. Программа может быть многопоточной, то есть внутри од-ного процесса может работать несколько параллельных потоков. На физическом уровне эти потоки обычно размещаются на разных ядрах многоядерного процессора. При этом разные потоки внутри одного процесса имеют разные сегменты стека, поскольку стек используется для поддержки вызовов и работы процедур, а в разных потоках одновременно могут быть запущены разные процедуры. Но сегменты кода и сегменты данных у потоков одной программы являются общими, поскольку в сег-менте кода хранится весь машинный код программы, и все потоки работают (могут работать) со все-ми данными программы.
Ранние ЭВМ использовались преимущественно для научных расчётов. Они имели не-большую оперативную память, но при этом требовалось, чтобы они обрабатывали данные, объем которых существенно превышал размер оперативной памяти, а также умели исполнять программы, объем кода которых превосходил объём оперативной памяти. Для этого использовался специальный приём, позволяющий загружать фрагменты данных и фрагменты машинного кода в оперативную память порциями, по мере необходимости. Это сильно усложняло код прикладных программ - про-граммисту приходилось самостоятельно реализовывать эту функциональность. Позже создатели ЭВМ второго и третьего поколений выработали общие подходы к решению этой задачи и вынесли её решение в операционную систему. Так появилась виртуальная память.
Виртуальная память (Virtual Memory) - это механизм работы программы/процесса с адресным пространством, превосходящим по размеру оперативную память ЭВМ или тот её фрагмент, который выделен данной программе/процессу.
При этом программа/процесс может работать с фрагментами разнородной физической па-мяти (включая жесткий диск), но адресное преобразование скрывает эту неоднородность, представ-ляя память для программы как единый, сплошной фрагмент и обеспечивая тем самым непрерывное адресное пространство.
Адресное пространство, доступное процессу, делится на виртуальные страницы. Для процессоров семейства Intel x86, работающих в 32-разрядном режиме, размер одной страницы составляет 4 Kb. Эти же процессоры, работающие в 64-разрядном режиме, поддерживают настраиваемый размер страниц от 4 Kb до 1 Mb. При этом оперативная па-мять делится физические страницы, размер которых совпадает с размером виртуальных страниц.
Операционная система выполняет страничное адресное преобразова-ние для того, чтобы связывать каждую виртуальную страницу с реальной памятью:
Windows это файл, в Unix-подобных ОС - раздел жёсткого диска).Возможно, что виртуальная страница не связана ни с каким реальным (физическим) фраг-ментом памяти. Это означает, что эта страница не инициализирована, то есть к ней ещё не было об-ращений из программы. Также страница может перейти в это состояние, если программе больше не нужны находящиеся в ней данные, и она явно "вернула" эту страницу операционной сис-теме.
Соответствие между страницами виртуальной памяти и физической памятью хранится в специальной структуре данных, которая называется таблица страниц и ко-торая располагается в оперативной памяти. Таблица страниц для всего адресного пространства получилась бы недопустимо большой, если хранить её в виде одного массива. Например, легко посчитать, что для адресного пространства 32-битного процессора Intel 80386 таблица страниц заняла бы до 4 Mb, в то время как общий объём оперативной памяти компьютеров на базе этого процессора обычно был равен 2 или 4 Mb. Поэтому в 32-разрядном режиме Intel x86 таблица страниц хранится в виде двухуровневой древовидной структуры, а в 64-разрядном режиме Intel x86_64 - в виде четырёхуровневой. Эти структуры заполняются постепенно, по мере использования программой виртуальных страниц.
В семействе процессоров Intel x86, начиная с Intel 80386, сегментная и страничная адресация могут использоваться одновременно. Вначале процессор делает сегментное преобразование, затем над получившемся адресом он выполняет страничное преобразо-вание, результатом которого уже является физический адрес.
Производители операционных систем для современных процессоров (например, Intel x86_64, ARM v7) постепенно отказываются от использования сегментной адресации, довольствуясь возможностями страничной. Применение одновременно сегментного и страничного адресных преобразований, как в Intel 80386, избыточно: виртуальная память строится только на основе страничного адресного преобразования. Процессоры семейства Intel x86 в 64-битном режиме не используют сегменты, поддерживая сегментную ад-ресацию лишь для совместимости со старыми программами. Многие архитектуры, отличные от Intel x86, сегментную адресацию не поддерживают вовсе.
До тех пор, пока программа не обратилась к памяти, виртуальные страницы её процесса не проинициализированы. При первом обращении программы к очередной странице процессор приостанавливает работу программы и передаёт управление операционной системе. Последняя выделяет для виртуальной страницы физическую страницу в оперативной памяти и обновляет таблицу страниц. Если свободных физических страниц нет, то операционная система выгружает данные из некоторой занятой физической страницы в область подкачки на жестком диске и выделяет процессу освободившуюся страницу.
Для выбора выгружаемой страницы используются стратегии вытесне-ния, аналогичные стратегиям вытеснения для кэш-памяти. Вытесненная виртуальная страница помечается как выгруженная, и при последующем обращении к ней процессор также передаёт управление операционной системе, чтобы она могла вновь выделить для этой страницы физическую страницу. Такой порядок работы виртуальной памяти позволяет процессу использовать большое ко-личество памяти, но реальную физическую память получать лишь по мере обращения к фрагментам этой памяти. При запуске процесс может запросить у операционной системы много памяти, но пока он не начал с ней работать, физическая память не будет расходоваться.
Читатель может легко убедиться в том, что современные операционные системы выделя-ют память описанным образом, написав следующую простую программу на C. Данная программа динамически, с помощью функции malloc, запрашивает большой объем памяти (на-пример, 1 Gb), но обращается к этой памяти не сразу, а по прошествии некоторого времени. Если проследить за запущенной программой (в случае Windows для этого достаточно дис-петчера процессов), то станет очевидно, что реальная физическая память выделяется не в момент вы-зова malloc, а по мере обращения к памяти из программы.
С и Java?С, пользуясь рекомендациями в конце данной лекции, чтобы увидеть действие стратегии вытеснения.Физический адрес, прямая адресация, адресное пространство про-граммы. Сегментная адресация: сегменты, их назначение, виртуальный адрес, адресное преобразо-вание; виртуальная память: страничная адресация, страницы, страничное адресное преобразование и их использование при реализации виртуальной памяти; замещение страниц физической памяти, выделение страниц по мере необходимости.
При старте программы операционная система создаёт для нее специальный процесс. Можно сказать, что процесс является экземпляром программы, точнее - запущенным на компьютере экземпляром. Как уже упоминалось выше, одновременно на компьютере может быть запущено не-сколько экземпляров одной и той же программы, с чем Вы, наверняка, сталкивались - например, работая в Windows, легко запустить несколько экземпляров текстового редактора "Блокнот". Далее мы иногда будем использовать термины процесс и программа как сино-нимы считая, что из контекста понятно, о чём идёт речь.
В оперативную память созданного процесса копируется код соответствующей программы, а также выделяется память для данных программы. Процессор взаимодействует с этой памятью посредством адресов. Система адресации у современных компьютеров оказывается непростой, и мы начнём её изучать с понятия физического адреса.
Физический адрес (Physical Address) - это номер ячейки в оперативной памяти. Зная этот номер, процессор непосредственно обращается в нужное место оперативной памяти за необходимыми данными.
Когда мы говорим об адресуемой ячейке в оперативной памяти, то мы имеем в виду ма-шинное слово, которое, как рассказывалось в предыдущих лекциях, является минимально адресуе-мый фрагмент памяти.
Многие ЭВМ прошлых поколений, а также простые современные вычислительные уст-ройства с позволяют своим программам обращаться к оперативной памяти напрямую, по физическо-му адресу, минуя всевозможные адресные преобразования, о которых пойдёт речь в этой лекции. Такая организация работы с памятью называется прямой адресацией.
Прямая адресация - это механизм использования в ма-шинном коде программ реальных физических адресов в оперативной памяти, без использования ад-ресных преобразований.
Хотя данная схема, на первый взгляд, выглядит естественной, она не обладает достаточ-ной гибкостью - ведь в действительности не всё так просто! Поэтому в современных персональных компьютерах, смартфонах, планшетах и других сложных вычислительных устройствах прямая адресация не применяется. И нам есть о чём поговорить в рамках данной лекции.
Дадим теперь определения адресного пространства программы. Казалось бы, это - вся оперативная память, которая выделяется процессу. Однако это не так, поскольку программа может оперировать с оперативной памятью большего объёма, чем выделено её процессу. Для этого исполь-зуется механизм виртуальной памяти, о котором речь пойдёт чуть ниже. А тут мы дадим корректное определение адресного пространства программы
Адресное пространство (Address Space) - это множество адресов, допустимое для использования программой.
В частности, значения указателей в программах на языке C, работающих на компьютерах семейства процессоров Intel x86, являются элементами адресного про-странства.
Память, которая выделяется процессу при старте операционной системой, является набо-ром сегментов.
Сегмент - это фрагмент оперативной памяти, выделяе-мый операционной системой процессу.
Размер и конкретное расположение сегментов процесса операционная система выбирает, исходя из следующих параметров:
Рассмотрим классическую (упрощённую) схему памяти процесса, когда эта память состо-ит из сегмента кода, сегмента данных и сегмента стека. Адреса внутри сегментов формируются как смещения относительно начала сегмента. Код программы знает о сегментах и оперирует этими сме-щениями. Например, в операции сложения вида регистр/память адрес в памяти для второго операнда указывается в виде смещения от начала сегмента данных (напомним, что именно там хранятся все переменные программы). Таким образом, реальный физический адрес, по которому должен обратиться процессор, вычисляются уже внутри процессора, а последний в свою очередь, знает физические адреса начала каждого сегмента. Итак, мы подошли к понятию виртуального адреса и адресного преобразования.
Адрес, с которым непосредственно работает программа, называет-ся виртуальным адресом (Virtual Address).
Адресное преобразование (Address Conversion) - это ме-ханизм вычисления физического адреса по виртуальному.
Отметим, что сегментная организация памяти процесса является не единственным источ-ником виртуальных адресов.
Рассмотрим теперь подробнее сегменты процесса.
Сегмент кода хранит в оперативной памяти машинный код про-граммы.
Сегмент данных хранит глобальные переменные программы (так называемые статические данные), а также используется для кучи (heap) в том случае, если в программе используются динамические данные. Размер всего сегмента данных известен во время запуска программы, но память для кучи выделяется в нём по мере исполнения программы, поскольку на мо-мент запуска не понятно, сколько программе понадобится динамической памяти - это зависит от конкретного сценария исполнения программы, поскольку динамическая память запрашивается с уровня прикладной программы, и её использование организует сам программист - автор програм-мы. Соответственно, куча является "динамическим пузырём" нефиксированного размера, "раздувающийся" по мере запросов программы.
В программах на языке C для того, чтобы запросить динамическую память, программист использует функцию malloc, а в C++ - оператор new. Поскольку динамическая память выделяется "в ручном" режиме, то и освобождаться она должна также "вручную", с помощью специальных функций (функция free в С, оператор delete в C++). Меха-низм динамической памяти требует от программиста внимательности и организованности, но взамен предоставляет гибкость и возможность создавать более эффективные программы. Однако при использовании этого механизма программист может допустить (и допускает!) сложно обнаружимые ошибки. Это стало причиной того, что в современных промышленных языках, таких как Java, C#, Python использование динамической памяти доступно только через выделение объектов, а не массивов байтов, как в C, а освобождение - посредством автоматической сборки мусора, освобождающей память объектов, на которые больше нет ссылок из программы.
Сегмент стека используется процессом для организации вызо-вов процедур (методов) программы. Он реализует структуру данных под названием стек.
Набор небольших однотипных фрагментов памяти, объединённых в список, в котором новый элемент всегда добавляется только в конец списка, и удаляться из этого списка может также с конца, называется стеком.
В тот момент, когда в программе выполняется вызов очередной процедуры, в сегмент стека помещаются следующие данные:
Совокупность перечисленных данных образует так называемый кадр стека (stack frame). Очевидно, что после завершения процедуры и продолже-ния выполнения программы в том контексте, откуда процедура была вызвана, ни ее локальные дан-ные, ни параметры больше не нужны. Поэтому кадр завершённой процедуры удаляется со стека, ос-вобождая место для других данных. Если процедура вызывается рекурсивно, то её кадры с различ-ными значениями параметров, данных, адреса возврата размещаются на стеке столько раз, сколько раз она была вызвана. Если программа зацикливается на рекурсивном вызове, то она помещает на стек всё больше и больше данных, заполняя всю допустимую для стека память, и после этого ава-рийно завершается с ошибкой "переполнение стека" (Stack Overflow). Эта ошибка настолько известна и распространена, что в честь неё названа самая популярная платформа вопросов-ответов по программированию StackOverflow ().
Сделаем следующую ремарку. Программа может быть многопоточной, то есть внутри од-ного процесса может работать несколько параллельных потоков. На физическом уровне эти потоки обычно размещаются на разных ядрах многоядерного процессора. При этом разные потоки внутри одного процесса имеют разные сегменты стека, поскольку стек используется для поддержки вызовов и работы процедур, а в разных потоках одновременно могут быть запущены разные процедуры. Но сегменты кода и сегменты данных у потоков одной программы являются общими, поскольку в сег-менте кода хранится весь машинный код программы, и все потоки работают (могут работать) со все-ми данными программы.
Ранние ЭВМ использовались преимущественно для научных расчётов. Они имели не-большую оперативную память, но при этом требовалось, чтобы они обрабатывали данные, объем которых существенно превышал размер оперативной памяти, а также умели исполнять программы, объем кода которых превосходил объём оперативной памяти. Для этого использовался специальный приём, позволяющий загружать фрагменты данных и фрагменты машинного кода в оперативную память порциями, по мере необходимости. Это сильно усложняло код прикладных программ - про-граммисту приходилось самостоятельно реализовывать эту функциональность. Позже создатели ЭВМ второго и третьего поколений выработали общие подходы к решению этой задачи и вынесли её решение в операционную систему. Так появилась виртуальная память.
Виртуальная память (Virtual Memory) - это механизм работы программы/процесса с адресным пространством, превосходящим по размеру оперативную память ЭВМ или тот её фрагмент, который выделен данной программе/процессу.
При этом программа/процесс может работать с фрагментами разнородной физической па-мяти (включая жесткий диск), но адресное преобразование скрывает эту неоднородность, представ-ляя память для программы как единый, сплошной фрагмент и обеспечивая тем самым непрерывное адресное пространство.
Адресное пространство, доступное процессу, делится на виртуальные страницы. Для процессоров семейства Intel x86, работающих в 32-разрядном режиме, размер одной страницы составляет 4 Kb. Эти же процессоры, работающие в 64-разрядном режиме, поддерживают настраиваемый размер страниц от 4 Kb до 1 Mb. При этом оперативная па-мять делится физические страницы, размер которых совпадает с размером виртуальных страниц.
Операционная система выполняет страничное адресное преобразова-ние для того, чтобы связывать каждую виртуальную страницу с реальной памятью:
Windows это файл, в Unix-подобных ОС - раздел жёсткого диска).Возможно, что виртуальная страница не связана ни с каким реальным (физическим) фраг-ментом памяти. Это означает, что эта страница не инициализирована, то есть к ней ещё не было об-ращений из программы. Также страница может перейти в это состояние, если программе больше не нужны находящиеся в ней данные, и она явно "вернула" эту страницу операционной сис-теме.
Соответствие между страницами виртуальной памяти и физической памятью хранится в специальной структуре данных, которая называется таблица страниц и ко-торая располагается в оперативной памяти. Таблица страниц для всего адресного пространства получилась бы недопустимо большой, если хранить её в виде одного массива. Например, легко посчитать, что для адресного пространства 32-битного процессора Intel 80386 таблица страниц заняла бы до 4 Mb, в то время как общий объём оперативной памяти компьютеров на базе этого процессора обычно был равен 2 или 4 Mb. Поэтому в 32-разрядном режиме Intel x86 таблица страниц хранится в виде двухуровневой древовидной структуры, а в 64-разрядном режиме Intel x86_64 - в виде четырёхуровневой. Эти структуры заполняются постепенно, по мере использования программой виртуальных страниц.
В семействе процессоров Intel x86, начиная с Intel 80386, сегментная и страничная адресация могут использоваться одновременно. Вначале процессор делает сегментное преобразование, затем над получившемся адресом он выполняет страничное преобразо-вание, результатом которого уже является физический адрес.
Производители операционных систем для современных процессоров (например, Intel x86_64, ARM v7) постепенно отказываются от использования сегментной адресации, довольствуясь возможностями страничной. Применение одновременно сегментного и страничного адресных преобразований, как в Intel 80386, избыточно: виртуальная память строится только на основе страничного адресного преобразования. Процессоры семейства Intel x86 в 64-битном режиме не используют сегменты, поддерживая сегментную ад-ресацию лишь для совместимости со старыми программами. Многие архитектуры, отличные от Intel x86, сегментную адресацию не поддерживают вовсе.
До тех пор, пока программа не обратилась к памяти, виртуальные страницы её процесса не проинициализированы. При первом обращении программы к очередной странице процессор приостанавливает работу программы и передаёт управление операционной системе. Последняя выделяет для виртуальной страницы физическую страницу в оперативной памяти и обновляет таблицу страниц. Если свободных физических страниц нет, то операционная система выгружает данные из некоторой занятой физической страницы в область подкачки на жестком диске и выделяет процессу освободившуюся страницу.
Для выбора выгружаемой страницы используются стратегии вытесне-ния, аналогичные стратегиям вытеснения для кэш-памяти. Вытесненная виртуальная страница помечается как выгруженная, и при последующем обращении к ней процессор также передаёт управление операционной системе, чтобы она могла вновь выделить для этой страницы физическую страницу. Такой порядок работы виртуальной памяти позволяет процессу использовать большое ко-личество памяти, но реальную физическую память получать лишь по мере обращения к фрагментам этой памяти. При запуске процесс может запросить у операционной системы много памяти, но пока он не начал с ней работать, физическая память не будет расходоваться.
Читатель может легко убедиться в том, что современные операционные системы выделя-ют память описанным образом, написав следующую простую программу на C. Данная программа динамически, с помощью функции malloc, запрашивает большой объем памяти (на-пример, 1 Gb), но обращается к этой памяти не сразу, а по прошествии некоторого времени. Если проследить за запущенной программой (в случае Windows для этого достаточно дис-петчера процессов), то станет очевидно, что реальная физическая память выделяется не в момент вы-зова malloc, а по мере обращения к памяти из программы.
С и Java?С, пользуясь рекомендациями в конце данной лекции, чтобы увидеть действие стратегии вытеснения.Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.