МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ КЫРГЫЗСКОЙ РЕСПУБЛИКИ КЫРГЫЗСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ им. И.РАЗЗАКОВА ИНСТИТУТ ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ КАФЕДРА «ИНФОРМАТИКА И ВЫЧИСЛИТЕЛЬНАЯ ТЕХНИКА» ПОЯСНИТЕЛЬНАЯ ЗАПИСКА к курсовой работе по дисциплине:” Операционные системы” Выполнил: Абдырахманова Нуржан Группа: ИВТ(КИ)-1-20 Руководитель работы(проекта): ________ Исраилова Н.А. Оценка: __________ БИШКЕК – 2023 Введение Цель данной симуляции состоит в исследовании и сравнительном анализе различных алгоритмов выделения страниц памяти в операционных системах. Она представляет собой инструмент для моделирования страничной организации памяти и оценки эффективности различных методов управления выделением страниц. Страничная организация памяти - важный аспект операционных систем, позволяющий эффективно управлять доступом к памяти компьютера. В рамках данной симуляции реализованы такие методы выделения страниц, как FIFO (First In First Out), OPT (Optimal Algorithm) и LRU (Least Recently Used). Приложение позволяет пользователям вводить последовательности страниц и выполнить симуляцию работы алгоритмов выделения страниц. Оно отображает состояние фреймов в определенные моменты времени, позволяя визуализировать процесс управления памятью и определять моменты возникновения промахов страниц. Целью данной симуляции является обеспечение удобного и понятного интерфейса для изучения и сравнения работы различных методов выделения страниц памяти. Она помогает выявить эффективные стратегии управления памятью, в зависимости от характеристик обрабатываемых данных и нагрузки на систему.. Цель и задача проекта Цель данного проекта заключается в исследовании и практическом применении концепций страничной организации памяти в операционных системах. Основной целью проекта является разработка программной модели подсистемы управления памятью, основанной на страничной организации, с использованием различных методов выделения памяти. Задачей проекта является создание программного инструмента, способного моделировать и анализировать процессы страничной организации памяти в операционных системах. Реализация программной модели будет включать анализ и применение методов выделения страниц памяти, таких как "First In First Out" (FIFO) и "Optimal Algorithm" (OPT), для эффективного управления процессами страниц и выделения памяти. Тематика исследования сфокусирована на изучении основных принципов страничной организации памяти, включая анализ эффективности различных методов выделения страниц и их влияние на общую производительность системы. Проект направлен на создание программной модели, которая позволит визуализировать и демонстрировать работу страничной организации памяти, а также изучить их преимущества и недостатки в различных сценариях использования операционных систем. Общее описание проекта Проект предполагает создание программной модели подсистемы управления памятью, основанной на страничной организации в операционной системе. В рамках проекта будет реализована система, способная разделять физическую память на отдельные страницы для хранения данных и процессов. Актуальность исследований: Современные вычислительные системы сталкиваются с постоянным увеличением требований к эффективному управлению памятью. Страничная организация памяти представляет собой важный и актуальный подход в этом контексте, поскольку она позволяет эффективно управлять физической памятью путем ее разделения на небольшие страницы. Этот подход имеет значительное преимущество в уменьшении фрагментации памяти - проблемы, возникающей при непрерывном выделении и освобождении блоков памяти различного размера. Страничная организация обеспечивает гибкость в управлении выделением и освобождением памяти для процессов, поскольку разделение памяти на страницы позволяет операционной системе лучше управлять обменом данных между физической памятью и внешним хранилищем, таким как жесткий диск. Это также способствует эффективному управлению виртуальной памятью и улучшает общую производительность операционной системы. Таким образом, исследование страничной организации памяти в современных системах является важным в контексте повышения эффективности управления памятью, обеспечения лучшей производительности и оптимизации работы операционных систем в целом.. Постановка задачи: Выполнение курсового проекта заключается в реализации программной модели подсистем операционной модели подсистем операционной системы, таких как подсистема управления процессами, подсистема управления памятью, файловая подсистема. Программная модель должна быть выполнена на языке Java. Вариант B-1 Страничное распределение памяти Функциональные требования Управление страницами: Реализация механизмов выделения и освобождения страниц памяти. Создание новых страниц для процессов. Освобождение страниц памяти после завершения процессов. Методы размещения страниц: Разработка механизмов для размещения страниц памяти на основе различных методов, таких как: FIFO (First In First Out) - вытеснение страницы, находящейся в памяти дольше всего. LRU (Least Recently Used) - вытеснение страницы, к которой было меньше всего обращений за определенный период. OPT (Optimal Algorithm) - оптимальное вытеснение страницы, которая дольше всего не будет использоваться. Управление фрагментацией: Обеспечение возможности эффективного управления фрагментацией памяти. Оптимизация использования ресурсов памяти при работе с процессами. Интерфейс пользователя: Создание удобного интерфейса для взаимодействия с программной моделью, позволяющего пользователям запускать симуляцию, управлять её выполнением (включение, остановка, шаг за шагом), а также просматривать результаты Технические требования Программная модель должна быть выполнена на языке C++. Реализация подсистемы управления процессами должна быть представлена в виде библиотеки функций DLL. Глава 1: Теоретическая часть. Виртуальное адресное пространство процесса делится на части одинакового, фиксированного для данной системы размера, называемые виртуальными страницами. Вся оперативная память машины также делится на части такого же размера, называемые физическими страницами. Размер страницы выбирается кратным степени двойки. При загрузке процесса часть его виртуальных страниц помещается в оперативную память, а остальные - на диск. Для каждого процесса ОС создает таблицу страниц – информационную структуру, содержащую записи обо всех виртуальных страниц процесса. Дескриптор страницы включает в себя следующую информацию: номер физической страницы, в которую загружена данная виртуальная страница; признак присутствия; признак модификации; признак обращения. Признаки присутствия, модификации и обращения в большинстве моделей современных процессоров устанавливаются аппаратно. Таблицы страниц, также как и описываемые ими страницы, размещаются в оперативной памяти. Адрес таблицы страниц включается в контекст соответствующего процесса. При активизации очередного процесса в специальный регистр процессора загружается адрес таблицы страниц данного процесса. При каждом обращении к памяти происходит чтение из таблицы страниц информации о виртуальной странице, к которой произошло обращение. Если данная виртуальная страница находится в оперативной памяти, то выполняется преобразование виртуального адреса в физический. Если же нужная виртуальная страница в данный момент выгружена на диск, то происходит так называемое страничное прерывание. Выполняющийся процесс переводится в состояние ожидания, и активизируется другой процесс из очереди готовых. Параллельно программа обработки страничного прерывания находит на диске требуемую виртуальную страницу и пытается загрузить ее в оперативную память. Если в памяти имеется свободная физическая страница, то загрузка выполняется немедленно, если же свободных страниц нет, то решается вопрос, какую страницу следует выгрузить из оперативной памяти. В данной ситуации может быть использовано много разных критериев выбора, наиболее популярные из них следующие: дольше всего не использовавшаяся страница; первая попавшаяся страница; страница, к которой в последнее время было меньше всего обращений. После того, как выбрана страница, которая должна покинуть оперативную память, анализируется ее признак модификации (из таблицы страниц). Если выталкиваемая страница с момента загрузки была модифицирована, то ее новая версия должна быть переписана на диск. Если нет, то cоответствующая физическая страница просто объявляется свободной. 42.Таблицы страниц для больших объемов памяти. Размер страницы влияет также на количество записей в таблицах страниц. Чем меньше страница, тем более объемными являются таблицы страниц процессов и тем больше места они занимают в памяти. Учитывая, что в современных процессорах максимальный объем виртуального адресного пространства процесса, как правило, не меньше 4 Гбайт, то при размере страницы 4 Кбайт и длине записи 4 байта для хранения таблицы страниц может потребоваться 4 Мбайт памяти. Что придумали: 1) Многоуровневые таблицы страниц. Достоинства: не надо иметь в памяти постоянно всю таблицу страниц, а только таблицу разделов; Недостатки: дополнительный этап преобразования адреса Для каждого раздела строится собственная таблица страниц. Количество дескрипторов в таблице и их размер подбираются такими, чтобы объем таблицы оказался равным объему страницы. Например, в процессоре Pentium при размере страницы 4 Кбайт длина дескриптора страницы составляет 4 байта и количество записей в таблице страниц, помещающейся на страницу, равняется соответственно 1024. Каждая таблица страниц описывается дескриптором, структура которого полностью совпадает со структурой дескриптора обычной страницы. Эти дескрипторы сведены в таблицу разделов, называемую также каталогом страниц. Физический адрес таблицы разделов активного процесса содержится в специальном регистре процессора и поэтому всегда известен операционной системе. Страница, содержащая таблицу разделов, никогда не выгружается из памяти, в противном случае работа виртуальной памяти была бы невозможна. 1.Путем отбрасывания k+n младших разрядов в виртуальном адресе определяется номер раздела, к которому принадлежит данный виртуальный адрес. 2.По этому номеру из таблицы разделов извлекается дескриптор соответствующей таблицы страниц. Проверяется, находится ли данная таблица страниц в памяти. Если нет, происходит страничное прерывание и система загружает нужную страницу с диска. 3.Далее из этой таблицы страниц извлекается дескриптор виртуальной страницы, номер которой содержится в средних п разрядах преобразуемого виртуального адреса. Снова выполняется проверка наличия данной страницы в памяти и при необходимости ее загрузка. 4.Из дескриптора определяется номер (базовый адрес) физической страницы, в которую загружена данная виртуальная страница. К номеру физической страницы пристыковывается смещение, взятое из к младших разрядов виртуального адреса. В результате получается искомый физический адрес. 2) Инвертированные таблицы страниц Достоинства: гораздо меньше по объёму. Недостатки: не совсем ясно, как в ней искать виртуальный адрес. Этот подход применяется на машинах PowerPC, некоторых рабочих станциях Hewlett-Packard, IBM RT, IBM AS/400 и ряде других. В этой таблице содержится по одной записи на каждый страничный кадр физической памяти. Существенно, что достаточно одной таблицы для всех процессов. Таким образом, для хранения функции отображения требуется фиксированная часть основной памяти, независимо от разрядности архитектуры, размера и количества процессов. Например, для компьютера Pentium c 256 Мбайт оперативной памяти нужна таблица размером 64 Кбайт строк. Несмотря на экономию оперативной памяти, применение инвертированной таблицы имеет существенный минус – записи в ней (как и в ассоциативной памяти) не отсортированы по возрастанию номеров виртуальных страниц, что усложняет трансляцию адреса. Один из способов решения данной проблемы – использование хеш-таблицы виртуальных адресов. При этом часть виртуального адреса, представляющая собой номер страницы, отображается в хеш-таблицу с использованием функции хеширования. Каждой странице физической памяти соответствует одна запись в хеш-таблице и инвертированной таблице страниц. Виртуальные адреса, имеющие одно значение хеш-функции, сцепляются друг с другом. Обычно длина цепочки не превышает двух записей. 43.Алгоритмы замещения страниц. 1) Оптимальный (нереализуемый) Каждая страница должна быть помечена количеством команд, которые выполняются до первого обращения к странице. Суть: на выгрузку выбирается страница, имеющая пометку наибольшим значением. 2)Исключение недавно использованных страниц Бит R – бит обращения, бит M – бит модификации. Суть: при запуске процесса R=0, M=0 для всех страниц. При каждом прерывании по таймеру бит R сбрасывается При возникновении ошибки отсутствия страницы ОС просматривает все дескрипторы страниц и делит их на четыре категории: Класс 0: ни обращений, ни модификации Класс 1: нет обращений, есть модификация Класс 2: есть обращения, нет модификации Класс 3: есть обращения, есть модификация Алгоритм удаляет произвольную страницу низшего класса. 3)Алгоритм «первый пришёл, первый ушёл» (FIFO) Страницы хранятся в связанном списке, по порядку загрузки. Выгружается та страница, которая стоит в начале списка (загружена первой) Достоинства: простой алгоритм. 4) «Второй шанс» Как в FIFO, но если у первой страницы бит R=0, то она удаляется, а если бит R=1, то он сбрасывается, а страница отправляется в конец списка. Если ко всем страницам есть обращение – вырождается в FIFO. 5) «Часы» Циклический список. Если R=0, страница выгружается, на её место загружается новая. Если R=1, то R сбрасывается, стрелка идёт дальше. 6)LRU – Least recently used 1Связанный список всех страниц. Первая страница – только что использованная. Использовали – переместили в начало. Недостатки: очень долгий даже на аппаратном уровне. 2 Страницам ввести счётчик. Удаляются страницы с наименьшим счётчиком Использовали - +1. 3 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 Если использовали страницу, элементы строки k увеличиваются на 1, элементы столбца k обнуляются. Удаляются страницы с наименьшим значением строки. 7) Алгоритм нечастого использования Программный счётчик, при каждом прерывании от таймера ОС сканирует все находящиеся в памяти страницы, если R=1, счётчик увеличивается на 1. Таким образом, кандидатом на освобождение оказывается страница с наименьшим значением счетчика, как страница, к которой реже всего обращались. Главный недостаток алгоритма NFU состоит в том, что он ничего не забывает. Например, страница, к которой очень часто обращались в течение некоторого времени, а потом обращаться перестали, все равно не будет удалена из памяти, потому что ее счетчик содержит большую величину. Например, в многопроходных компиляторах страницы, которые активно использовались во время первого прохода, могут надолго сохранить большие значения счетчика, мешая загрузке полезных в дальнейшем страниц. К счастью, возможна небольшая модификация алгоритма, которая позволяет ему "забывать". Достаточно, чтобы при каждом прерывании по времени содержимое счетчика сдвигалось вправо на 1 бит, а уже затем производилось бы его увеличение для страниц с установленным флагом обращения. Другим, уже более устойчивым недостатком алгоритма является длительность процесса сканирования таблиц страниц. 8) «Рабочий набор» Рабочий набор - множество страниц (к), которое процесс использовал до момента времени (t). Т.е. можно записать функцию w(k,t). Т.е. рабочий набор выходит в насыщение, значение w(k,t) в режиме насыщения может служить для рабочего набора, который необходимо загружать до запуска процесса. Алгоритм заключается в том, чтобы определить рабочий набор, найти и выгрузить страницу, которая не входит в рабочий набор. Этот алгоритм можно реализовать, записывая, при каждом обращении к памяти, номер страницы в специальный сдвигающийся регистр, затем удалялись бы дублирующие страницы. Но это дорого. В принципе можно использовать множество страниц, к которым обращался процесс за последние t секунд. Текущее виртуальное время (Tv) - время работы процессора, которое реально использовал процесс. Время последнего использования (Told) - текущее время при R=1, т.е. все страницы проверяются на R=1, и если да то текущее время записывается в это поле. Теперь можно вычислить возраст страницы (не обновления) Tv-Told, и сравнить с t, если больше, то страница не входит в рабочий набор, и страницу можно выгружать. Получается три варианта: если R=1, то текущее время запоминается в поле время последнего использования если R=0 и возраст > t, то страница удаляется если R=0 и возраст =< t, то эта страница входит в рабочий набор 9) WSClock Алгоритм основан на алгоритме "часы", но использует рабочий набор. Используются битов R и M, а также время последнего использования. Это достаточно реальный алгоритм, который используется на практике. Глава 2: Разработка проекта. Код проекта: Логика FIFO: package com.github.pageallocation.algorithms; import java.util.LinkedList; import com.github.pageallocation.algorithms.model.Frames; import com.github.pageallocation.algorithms.model.Reference; public class FIFOPageReplacement extends AbstractPageReplacement { @Override protected void allocate() { LinkedList<Integer> queue = new LinkedList<>(); Frames past = new Frames(frames); for(Reference r: references){ int ref = r.getReference(); Frames f = r.getFrames(); f.copyAll(past); System.out.println("FIFOAlloc.allocate( )" + ref + " " + f.contains(ref)); if(!f.contains(ref)){ faults++; queue.addLast(ref); if(f.thereIsAnEmptyFrame()){ System.out.println("empty"); f.set(f.getEmptyFrame(), ref); }else{ System.out.println("victim"); int victim = queue.removeFirst(); f.swap(victim, ref); } } past.copyAll(f); } } } Логика LRUP: package com.github.pageallocation.algorithms; import java.util.LinkedList; import com.github.pageallocation.algorithms.model.Frames; import com.github.pageallocation.algorithms.model.Reference; public class LRUPageReplacement extends AbstractPageReplacement { @Override protected void allocate() { LinkedList<Integer> queue = new LinkedList<>(); Frames past = new Frames(frames); for(Reference r: references){ int ref = r.getReference(); Frames f = r.getFrames(); f.copyAll(past); queue.remove(Integer.valueOf(ref)); queue.addLast(ref); System.out.println("FIFOAlloc.allocate( )" + ref + " " + f.contains(ref)); if(!f.contains(ref)){ faults++; if(f.thereIsAnEmptyFrame()){ f.set(f.getEmptyFrame(), ref); }else{ int victim = queue.removeFirst(); f.swap(victim, ref); } } past.copyAll(f); } } } Логика OPT: package com.github.pageallocation.algorithms; import com.github.pageallocation.algorithms.model.Frames; import com.github.pageallocation.algorithms.model.Reference; public class OPTPageReplacement extends AbstractPageReplacement { @Override protected void allocate() { Frames past = new Frames(frames); for(Reference r: references){ int ref = r.getReference(); Frames f = r.getFrames(); f.copyAll(past); if(!f.contains(ref)){ faults++; if(f.thereIsAnEmptyFrame()){ f.set(f.getEmptyFrame(), ref); }else{ int victim = getLastReferenced(f); f.swap(victim, ref); } } past.copyAll(f); refs.remove(0); } } private int getLastReferenced(Frames f){ int last = -1; int lastOne=-1; for(int i =0; i < frames; i++){ int victim = f.get(i); int index = refs.indexOf(victim); if(index == -1){ return victim; } else if(index > last){ last = index; lastOne = victim; } } return lastOne; } } SimulationPanel package com.github.pageallocation.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import import import import import javax.swing.JLabel; javax.swing.JPanel; javax.swing.JScrollPane; javax.swing.JTable; javax.swing.JTextField; import import import import com.github.pageallocation.algorithms.PageReplacementStrategy; com.github.pageallocation.gui.table.MyDefaultTableModel; com.github.pageallocation.gui.table.PageFaultRenderer; com.github.pageallocation.simulation.PageAllocationSimulation; public class SimulationPanel extends JPanel { private static final long serialVersionUID = 1L; private JTable table; String algorithm; String tooltipText; JScrollPane sc; JLabel label; private PageReplacementStrategy strategy; private PageAllocationSimulation simulation; private JTextField faults; private JTextField faultRate; static String[] columnNames = { "Frames", "A", "B", "C", "D", "E", "F", "G" }; static String[][] data = new String[4][8]; // Rows, Columns static { for (int i = 0; i < 4; i++) data[i][0] = "" + i; } private MyDefaultTableModel model; public SimulationPanel(String algorithmName, String tooltipText, PageReplacementStrategy strategy) { init(algorithmName, tooltipText, strategy); } private void init(String algorithmName, String toolTipText, PageReplacementStrategy strategy) { this.algorithm = algorithmName; this.setStrategy(strategy); label = new JLabel(algorithmName); label.setToolTipText(tooltipText); label.setPreferredSize(new Dimension(50, 25)); this.add(label); setModel(new MyDefaultTableModel(data, columnNames)); setTable(new JTable(getModel())); getTable().setDefaultRenderer(Object.class, new PageFaultRenderer()); getTable().setCellSelectionEnabled(false); getTable().setAutoResizeMode(JTable.AUTO_RESIZE_OFF); // table.setAutoCreateColumnsFromModel(false); getTable().setEnabled(false); sc = new JScrollPane(getTable()); sc.setPreferredSize(new Dimension(600, 98)); sc.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); sc.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); this.add(sc); this.add(pageFaultsDisplay(), BorderLayout.EAST); setSimulation(new PageAllocationSimulation(table,model)); } private JPanel pageFaultsDisplay() { JLabel label; JPanel panelTotal = new JPanel(); panelTotal.setLayout(new BorderLayout()); JPanel panelTop = new JPanel(); panelTop.setLayout(new BorderLayout()); setFaults(new JTextField()); getFaults().setEditable(false); getFaults().setBackground(Color.LIGHT_GRAY); panelTop.add(getFaults(), BorderLayout.CENTER); JPanel panelBot = new JPanel(); panelBot.setLayout(new BorderLayout()); setFaultRate(new JTextField()); getFaultRate().setEditable(false); getFaultRate().setBackground(Color.LIGHT_GRAY); panelBot.add(getFaultRate(), BorderLayout.CENTER); panelTotal.add(panelTop, BorderLayout.NORTH); panelTotal.add(panelBot, BorderLayout.CENTER); return panelTotal; } public void clear() { getFaults().setText(""); getFaultRate().setText(""); getModel().setDataVector(data, columnNames); getModel().fireTableDataChanged(); getSimulation().clearParams(); strategy.clearStats(); } public MyDefaultTableModel getModel() { return model; } public void setModel(MyDefaultTableModel model) { this.model = model; } public JTextField getFaults() { return faults; } public void setFaults(JTextField faults) { this.faults = faults; } public JTextField getFaultRate() { return faultRate; } public void setFaultRate(JTextField faultRate) { this.faultRate = faultRate; } public JTable getTable() { return table; } public void setTable(JTable table) { this.table = table; } PageReplacementStrategy getStrategy() { return strategy; } void setStrategy(PageReplacementStrategy strategy) { this.strategy = strategy; } public PageAllocationSimulation getSimulation() { return simulation; } public void setSimulation(PageAllocationSimulation simulation) { this.simulation = simulation; } } UserInterface { private private private private private static final int MINIMUM_REFERENCE_LENGTH = 7; static final long serialVersionUID = 1L; JFrame f; Container contentPane; JTextArea randStrArea; private SpinnerNumberModel strLengthModel, frameSpinnerModel, rangeSpinnerModel; private PropertiesWindow propWin = new PropertiesWindow(); private List<SimulationPanel> simulationPanels = new ArrayList<>(3); private SimulationRunnerManager simManager; private JButton play, pause; private final StateManager state; private final Pattern REFERENCES_PATTERN = Pattern .compile("(\\d+){1}(,\\s*\\d*)*"); public UserInterface() { createSimulationPanels(); f = new JFrame(); contentPane = f.getContentPane(); f.setJMenuBar(menuBar()); contentPane.add(northPanel(), BorderLayout.NORTH); contentPane.add(centerPanel(), BorderLayout.CENTER); if (getOS().contains("win")) f.setSize(780, 560); else f.setSize(800, 560); f.setLocation(setFrameCentered()); f.setResizable(true); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); state = new StateManager(); f.setVisible(true); } private void createSimulationPanels() { simulationPanels.add(new SimulationPanel("FIFO", "First in First Out", new FIFOPageReplacement())); simulationPanels.add(new SimulationPanel("OPT", "Optimal Algorithm", new OPTPageReplacement())); simulationPanels.add(new SimulationPanel("LRU", "Least Recently Used", new LRUPageReplacement())); } private JPanel northPanel() { JPanel p = new JPanel(new BorderLayout()); p.add(northWestPanel(), BorderLayout.WEST); p.add(northEastPanel(), BorderLayout.EAST); return p; } private JPanel northEastPanel() { JPanel topLayer = new JPanel(new BorderLayout()); topLayer.setBorder(BorderFactory.createEmptyBorder(10, 15, 0, 15)); JPanel north = new JPanel(); JPanel south = new JPanel(); JPanel west = new JPanel(); JLabel label; JSpinner spinner; randStrArea = new JTextArea(); randStrArea.setLineWrap(true); JScrollPane scrollPane = new JScrollPane(randStrArea); scrollPane .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); scrollPane.setPreferredSize(new Dimension(470, 80)); // Width, Height north.add(scrollPane); JButton button; button = new JButton(); button.setPreferredSize(new Dimension(85, 25)); button.setIcon(Resources.RESET.getIcon()); button.setToolTipText("Reset Simulation"); button.setFocusPainted(false); button.setActionCommand("reset"); button.addActionListener(this); south.add(button); play = new JButton(); play.setPreferredSize(new Dimension(85, 25)); play.setIcon(Resources.PLAY.getIcon()); play.setToolTipText("Run Simulation"); play.setFocusPainted(false); play.setActionCommand("run"); play.addActionListener(this); south.add(play); pause = new JButton(); pause.setPreferredSize(new Dimension(85, 25)); pause.setIcon(Resources.PAUSE.getIcon()); pause.setToolTipText("Pause Simulation"); pause.setFocusPainted(false); pause.setActionCommand("pause"); pause.addActionListener(this); pause.setEnabled(false); south.add(pause); button = new JButton("Генерация"); button.setPreferredSize(new Dimension(110, 25)); button.setToolTipText("Количество страниц"); button.setFocusPainted(false); button.setActionCommand("генерировать"); button.addActionListener(this); south.add(button); label = new JLabel("Количество блоков памяти"); west.add(label); frameSpinnerModel = new SpinnerNumberModel(3, 3, 100, 1); spinner = new JSpinner(frameSpinnerModel); spinner.setPreferredSize(new Dimension(55, 25)); west.add(spinner); if (getOS().contains("mac")) west.setLayout(new FlowLayout(FlowLayout.CENTER, 8, 0)); else if (getOS().contains("win")) west.setLayout(new FlowLayout(FlowLayout.CENTER, 16, 0)); else west.setLayout(new FlowLayout(FlowLayout.CENTER, 6, 0)); label = new JLabel("Количество страниц"); label.setToolTipText("Numbers to Generate"); west.add(label); strLengthModel = new SpinnerNumberModel(MINIMUM_REFERENCE_LENGTH, MINIMUM_REFERENCE_LENGTH, 99, 1); spinner = new JSpinner(strLengthModel); if (getOS().contains("mac")) spinner.setPreferredSize(new Dimension(45, 25)); else spinner.setPreferredSize(new Dimension(35, 25)); west.add(spinner); topLayer.add(north, BorderLayout.NORTH); topLayer.add(west, BorderLayout.WEST); topLayer.add(south, BorderLayout.SOUTH); return topLayer; } private JPanel northWestPanel() { JPanel p = new JPanel(); ImageIcon i = Resources.SIMULATOR.getIcon(); JLabel label = new JLabel(i); JLabel buffer = new JLabel(); buffer.setPreferredSize(new Dimension(18, 0)); p.add(buffer); p.add(label); return p; } private JPanel centerPanel() { JPanel topLayer = new JPanel(new FlowLayout()); for (SimulationPanel alg : simulationPanels) { topLayer.add(alg); } return topLayer; } private JMenuBar menuBar() { JMenuBar mb = new JMenuBar(); JMenu fileMenu, helpMenu; JMenuItem run, step, reset, properties, exit, help, about; // JMenu's fileMenu = new JMenu("File"); helpMenu = new JMenu("Help"); fileMenu.setRolloverEnabled(true); helpMenu.setRolloverEnabled(true); // JMenuItem's run = new JMenuItem("Run"); run.setIcon(Resources.PLAY.getIcon()); reset = new JMenuItem("Reset"); reset.setIcon(Resources.RESET.getIcon()); // Add JMenuItem's to the JMenu's fileMenu.add(run); fileMenu.add(reset); fileMenu.addSeparator(); fileMenu.addSeparator(); // Accelerator run.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.CTRL_MASK)); reset.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK)); // Action Listening run.setActionCommand("run"); run.addActionListener(this); reset.setActionCommand("reset"); reset.addActionListener(this); return mb; } private Point setFrameCentered() { Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int w = f.getSize().width; int h = f.getSize().height; int x = (d.width - w) / 2; int y = (d.height - h) / 2; Point p = new Point(x, y - 20); return p; } private String getOS() { String s = System.getProperty("os.name").toLowerCase(); return s; } private void addContent(JTextArea t, String f) { String line; try { InputStream iStream = getClass().getClassLoader() .getResourceAsStream(f); InputStreamReader isr = new InputStreamReader(iStream); BufferedReader reader = new BufferedReader(isr); while ((line = reader.readLine()) != null) { t.append(line); t.append("\n"); } iStream.close(); isr.close(); reader.close(); } catch (Exception e) { System.out.println("Error: " + e.getMessage()); } } private void populateSimulationTable(int[] s) { if (s == null) return; if (simManager != null) { simManager.stopSimulation(); } List<Simulation> simulations = new ArrayList<>( this.simulationPanels.size()); PageReplacementStrategy strategy = null; DecimalFormat fmt = new DecimalFormat("###.##"); int frames = frameSpinnerModel.getNumber().intValue(); for (SimulationPanel simulationPanel : simulationPanels) { int columns = simulationPanel.getTable().getColumnCount(); strategy = simulationPanel.getStrategy(); strategy.setParams(s, frames); PageAllocationSimulation sim = simulationPanel.getSimulation(); sim.setParams(strategy.allocateReferences(), frames, columns); simulations.add(sim); simulationPanel.getFaults().setText(Integer.toString(strategy.faults())); simulationPanel.getFaultRate().setText( fmt.format(strategy.faultRate()) + "%"); } simManager = new SimulationRunnerManager(new CompositeSimulation( simulations), propWin); simManager.addListener(state); } private void updateSimulationTablesColumns(int[] s) { Object[] header = Util.makeHeaderArray(s); for (SimulationPanel sims : simulationPanels) { updateSimulationColumns(s, sims, header); } } private void updateSimulationColumns(int[] s, SimulationPanel simulationPanel, Object[] headers) { MyDefaultTableModel model = simulationPanel.getModel(); model.setRowCount(s.length + 1); model.setColumnIdentifiers(headers); model.fireTableStructureChanged(); } private void updateSimulationTablesRows() { int frames = frameSpinnerModel.getNumber().intValue(); for (SimulationPanel sims : simulationPanels) { DefaultTableModel model = sims.getModel(); model.setRowCount(0); for (int i = 0; i < frames; i++) { model.addRow(new Object[] { i }); } } } @Override public void actionPerformed(ActionEvent e) { String actionCommand = e.getActionCommand(); // Menubar if (actionCommand.equals("exit")) { System.exit(0); } else if (actionCommand.equals("help")) { JTextArea textArea = new JTextArea(); addContent(textArea, "README.txt"); textArea.setEditable(false); textArea.setCaretPosition(NORMAL); JScrollPane sc = new JScrollPane(textArea); sc.setPreferredSize(new Dimension(634, 250)); // Width, Height sc.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); JOptionPane.showMessageDialog(f, sc, "Help", JOptionPane.QUESTION_MESSAGE); } else if (actionCommand.equals("about")) { // JOptionPane.showMessageDialog(f, "Version: " + version + "\n" // + "Author: Victor J. Reventos" + "\n" // + "GUI Based on: \n" + " Adam Childs\n" // + " Shawn Craine\n" + " Dylan Meyer\n", "About", // JOptionPane.INFORMATION_MESSAGE); } // Buttons else if (actionCommand.equals("reset")) { resetGui(); } else if (actionCommand.equals("properties")) { propWin.setVisible(true); } else if (actionCommand.equals("run")) { runOrStepSimulation(false); } else if (actionCommand.equals("stop")) { stopSimulation(); } else if (actionCommand.equals("step")) { runOrStepSimulation(true); }else if (actionCommand.equals("pause")) { pauseSimulation(); } else if (actionCommand.equals("generate")) { int i = strLengthModel.getNumber().intValue(); randStrArea.setText(Util.generateRandomPageReference(i, rangeSpinnerModel.getNumber().intValue())); } } private void pauseSimulation() { System.out.println("UserInterface.pauseSimulation()"); simManager.pause(); } private void stopSimulation() { System.out.println("UserInterface.stopSimulation() " + state.simManagerRunning); simManager.stopSimulation(); } private void runOrStepSimulation(boolean step) { String text = randStrArea.getText(); if (text.equals("") || !isValidInputReferencesFormat(text)) { JOptionPane.showMessageDialog(f, "Error! Invalid format. Please\n" + "generate or supply a string of numbers\n" + "with a comma and space between each\n" + "number.", "String Error", JOptionPane.ERROR_MESSAGE); } else { if (state.simManagerRunning) { if (step) { simManager.step(); } else { simManager.play(); } return; } int[] s = Util.refStringToArray(text); if (!(s.length < MINIMUM_REFERENCE_LENGTH)) { updateSimulationTables(s); populateSimulationTable(s); if (step) { simManager.step(); } else { simManager.play(); } } else { JOptionPane.showMessageDialog(f, "You must supply a string of\n" + "at least 7 numbers. Remember\n" + "to separate each number by a\n" + "comma and a space.", "String Error", JOptionPane.ERROR_MESSAGE); } s = null; } } private boolean isValidInputReferencesFormat(String text) { return REFERENCES_PATTERN.matcher(text).matches(); } private void updateSimulationTables(int[] s) { updateSimulationTablesColumns(s); updateSimulationTablesRows(); } /** * If there is a simulation stop it. Clear all the simulation panels and * make the initial state. */ private void resetGui() { if (simManager != null) { simManager.stopSimulation(); } for (SimulationPanel sim : simulationPanels) { sim.clear(); } state.initState(); } class StateManager implements SimulationStateListener { private boolean simManagerRunning; public StateManager() { initState(); } void initState() { play.setEnabled(true); pause.setEnabled(false); //step.setEnabled(true); simManagerRunning = false; } @Override public void stepEvent(SimulationStateEvent e) { System.out.println("UserInterface.StateManager.stepEvent()"); play.setEnabled(true); pause.setEnabled(false); simManagerRunning = true; } @Override public void playEvent(SimulationStateEvent e) { System.out.println("UserInterface.StateManager.playEvent()"); play.setEnabled(false); pause.setEnabled(true); simManagerRunning = true; } @Override public void pauseEvent(SimulationStateEvent e) { System.out.println("UserInterface.StateManager.pauseEvent()"); play.setEnabled(true); pause.setEnabled(false); } @Override public void stopEvent(SimulationStateEvent e) { System.out.println("UserInterface.StateManager.stopEvent()"); play.setEnabled(false); pause.setEnabled(false); step.setEnabled(false); // simManagerRunning = false; simManager.stopSimulation(); JOptionPane.showMessageDialog(f, "Simulation Finished", "Simulation", JOptionPane.INFORMATION_MESSAGE); } } } Инструкция для симуляции: Возле кнопки "Generate" находится текстовое поле, где пользователь может указать общую длину строки случайно сгенерированных чисел. Эта строка содержит от 7 до 99 чисел. Пользователь может переключать кнопку, чтобы выбрать, сколько случайно сгенерированных чисел он хотел бы получить в строке. С другой стороны, пользователь может ввести строку по своему выбору, тем самым тестировать свою собственную строку чисел. Введенная строка должна быть разделена запятыми. После генерации или создания собственной строки пользователь может использовать управляющие кнопки следующим образом: Кнопка Сочетание клавиш Run CTRL+R Reset CTRL+Z Для управления выполнением симуляции. Симуляция состоит из таблицы и соответствующего алгоритма выделения. Каждый столбец представляет состояние кадров на момент обращения к ним. Промах страницы представлен путем раскраски столбца, в котором произошел промах страницы. Ячейка, содержащая 'X', соответствует кадру, который не был выделен. Справа от каждой таблицы пользователь может просмотреть количество промахов страницы и коэффициент промахов страницы для каждого метода выделения для заданного ввода (строка чисел, количество кадров, диапазон чисел в строке). FIFO (First In First Out): Описание: Этот метод основан на принципе "первый пришел, первый ушел". Страница, которая была загружена в память первой, вытесняется первой, когда требуется место для новой страницы. Работа: Осуществляется очередь кадров памяти, и новые страницы замещаются теми, которые были загружены в память раньше всех, что может привести к эффекту старения, когда давно находящиеся в памяти страницы могут быть вытеснены, несмотря на их актуальность. OPT (Optimal Algorithm): Описание: Этот метод выбирает страницу для вытеснения, которая наиболее долго не будет использоваться в будущем, то есть использует "идеальное предположение" о том, какие страницы будут запрошены в будущем. Работа: Для реализации этого метода требуется информация о том, какие страницы будут запрошены в будущем. Однако на практике это невозможно предсказать, поэтому OPT рассматривается как идеальный метод, который показывает, как хорошо или плохо работают другие алгоритмы. LRU (Least Recently Used): Описание: Этот метод замещает страницу, которая была меньше всего использована в последнее время. Работа: При каждом обращении к странице она помечается как недавно использованная. Таким образом, при необходимости вытеснения страницы выбирается та, которая была меньше всего использована в прошлом. Заключение. Проведенная работа в области симуляции страничной организации памяти и анализа различных методов распределения позволила глубже понять принципы функционирования алгоритмов управления памятью в операционных системах. В процессе данного исследования были рассмотрены и сравнены три основных метода: FIFO, OPT и LRU. Каждый из них обладает своими преимуществами и недостатками, которые становятся заметными в различных сценариях использования. Метод FIFO, основанный на принципе "первый вошел, первый вышел", демонстрирует простоту реализации, но может столкнуться с проблемой несправедливого вытеснения актуальных данных из памяти. OPT, использующий оптимальное предположение о будущем использовании страниц, показывает теоретически идеальные результаты, но в реальных условиях требует информации о будущих запросах, что делает его сложным для практической реализации. LRU, основанный на принципе вытеснения страниц, которые были реже всего использованы, является более практичным подходом, однако требует постоянного отслеживания времени последнего использования каждой страницы. Таким образом, результаты проведенного исследования подчеркивают важность выбора оптимального алгоритма управления памятью, учитывая специфику задач и характеристики рабочей нагрузки системы. Полученные выводы позволяют лучше понять, каким образом различные методы управления памятью влияют на общую производительность системы и насколько важно адаптировать выбранный алгоритм под конкретные условия работы. Дальнейшие исследования в этой области позволят углубить понимание механизмов управления памятью и разработать более эффективные и оптимальные методы для обеспечения стабильной и эффективной работы операционных систем в различных сценариях использования. Результаты настоящего исследования представляют собой важный вклад в понимание и развитие алгоритмов управления памятью, что будет полезно для дальнейших исследований в области оптимизации работы операционных систем.