Pamięć wirtualna

Z lewej pamięć wirtualna jednego z procesów, z prawej jej rozmieszczenie w pamięci fizycznej

Pamięć wirtualna – mechanizm zarządzania pamięcią komputera zapewniający procesowi wrażenie pracy w jednym, dużym, ciągłym obszarze pamięci operacyjnej, podczas gdy fizycznie może być ona pofragmentowana, nieciągła i częściowo przechowywana na urządzeniach pamięci masowej. Systemy korzystające z tej techniki ułatwiają tworzenie rozbudowanych aplikacji oraz poprawiają wykorzystanie fizycznej pamięci RAM w systemach wielozadaniowych. Często popełnianym błędem jest utożsamianie pamięci wirtualnej z wykorzystaniem pamięci masowej do rozszerzenia dostępnej pamięci operacyjnej. Rozszerzenie pamięci na dyski twarde w rzeczywistości jest tylko naturalną konsekwencją zastosowania techniki pamięci wirtualnej, lecz może być osiągnięte także na inne sposoby, np. nakładki lub całkowite przenoszenie pamięci procesów na dysk, gdy znajdują się w stanie uśpienia. Pamięć wirtualna działa na zasadzie przedefiniowania adresów pamięci (fizycznych) na adresy używane przez procesy (logiczne) tak, aby „oszukać” procesy i dać im wrażenie pracy w ciągłej przestrzeni adresowej. Pamięć wirtualna oznacza znacznie większą ilość pamięci RAM dla procesu niż fizycznie dostępna w systemie[1].

Obecnie wszystkie systemy operacyjne ogólnego przeznaczenia wykorzystują techniki pamięci wirtualnej dla procesów uruchamianych w ich obrębie. Wcześniejsze systemy takie, jak DOS, wydania Microsoft Windows[2] z lat 80. oraz oprogramowanie komputerów mainframe z lat 60. nie pozwalały pracować w środowisku z pamięcią wirtualną. Godnymi odnotowania wyjątkami były komputery Atlas, B5000 oraz Apple Lisa.

Pamięć wirtualna wymaga wykonania dodatkowych nakładów pracy procesora przy odczycie i zapisie do pamięci, nakłady te występują tylko czasami i trwają dość długo, dlatego systemy czasu rzeczywistego lub szczególnego przeznaczenia, w których czas jest czynnikiem krytycznym i musi być przewidywalny, często nie korzystają lub ograniczają stosowanie mechanizmu pamięci wirtualnej.

Dyski twarde są około 100 razy wolniejsze od pamięci o dostępie swobodnym, przez co uruchamianie programów wymagających ilości pamięci większej niż fizycznie zainstalowana pamięć RAM powoduje wolne działanie komputera.

Historia

W pierwszych komputerach z lat 40. i 50., podobnie jak współcześnie, pamięć była zorganizowana w sposób dwupoziomowy, analogicznie do obecnego podziału na RAM i pamięć masową. Jednak z powodu braku mechanizmów pamięci wirtualnej, każdy program musiał we własnym zakresie zarządzać przenoszeniem danych z jednego poziomu do drugiego, co komplikowało programowanie. Głównym powodem wprowadzenia pamięci wirtualnej była zatem chęć maksymalnego uproszczenia i automatyzacji procesów związanych z zarządzaniem pamięcią, a nie jej rozszerzenie[3].

Wraz z pojawieniem się wielozadaniowości, wiodące systemy zaczęły udostępniać proste mechanizmy współdzielenia pamięci przez kilka uruchomionych procesów oparte na prostych technikach segmentacji. Dostępna dla procesu pamięć rozpoczynała się od adresu zerowego, a jej koniec wyznaczany był przez wartość rejestru granicznego. Aby uzyskać adres fizyczny, należało dodać do żądanego adresu logicznego wartość rejestru bazowego wyznaczającego przesunięcie. Takie rozwiązanie zostało m.in. zaimplementowane w komputerze PDP-10.

Pamięć wirtualna została zaprojektowana między rokiem 1959 a 1962 na Uniwersytecie Manchester dla komputera Atlas, który został ukończony w 1962 roku[4]. Jednak niemiecki informatyk Fritz-Rudolf Güntsch, późniejszy twórca komputera Telefunken TR 440 twierdzi, że zaproponował tę technikę w roku 1957 w swojej pracy doktorskiej Logischer Entwurf eines digitalen Rechengerätes mit mehreren asynchron laufenden Trommeln und automatischem Schnellspeicherbetrieb.

W roku 1961 ukazał się B5000 firmy Burroughs, pierwszy komercyjny komputer z pamięcią wirtualną[5]. Zamiast stronicowania, korzystał z mechanizmu segmentacji pamięci.

Stronicowanie pamięci, podobnie jak wiele innych nowych technologii w historii informatyki, wzbudzało początkowo wiele kontrowersji. Zanim zaczęło być stosowane na szerszą skalę, konieczne było stworzenie szeregu modeli, eksperymentów i teorii w celu rozwiązania nowo napotkanych problemów. Dynamiczne tłumaczenie adresów wymagało zastosowania specjalistycznych, drogich i ciężkich do zbudowania układów elektronicznych, a ponadto początkowo znacznie spowalniało dostęp do pamięci. Pojawiały się obawy, że nowe algorytmy zarządzania pamięcią dyskową będą dużo mniej efektywne od dotychczasowych, dostosowanych do potrzeb konkretnych aplikacji. Do roku 1969 debata została zakończona. Ekipa badawcza IBM pod przewodnictwem Davida Sayre jednoznacznie wykazała, że systemy z pamięcią wirtualną działają sprawniej, niż najlepsze systemy z własnymi mechanizmami.

Pamięć wirtualna została wprowadzona do architektury x86 wraz z pojawieniem się trybu chronionego w procesorze Intel 80286. Na początku realizowana była techniką segmentacji, która okazała się być nieefektywna przy większych segmentach. Procesor Intel 80286 wprowadził dodatkowo stronicowanie zbudowane na bazie już istniejącego systemu segmentacji.

Stronicowana pamięć wirtualna

Prawie wszystkie istniejące obecnie implementacje dzielą wirtualną przestrzeń adresową procesu na strony. Strona to obszar ciągłej pamięci o stałym rozmiarze (zazwyczaj 4 kB). Systemy, gdzie zapotrzebowanie na wielkość wirtualnej przestrzeni adresowej jest większe lub dysponujące większymi zasobami pamięci operacyjnej mogą używać stron o większym rozmiarze. Rzeczywista pamięć operacyjna podzielona jest na ramki, których rozmiar odpowiada wielkości stron. System operacyjny według uznania może przydzielać ramkom strony pamięci lub pozostawiać je puste.

Tablice stron

Każde odwołanie przez dany proces do wirtualnego adresu pamięci powoduje jego przetłumaczenie na adres fizyczny przy pomocy tablicy stron. Wpisy w tablicy stron przechowują namiary na ramkę, gdzie aktualnie znajduje się dana strona lub znacznik informujący, że dana strona znajduje się aktualnie na dysku twardym.

Systemy mogą utrzymywać tylko jedną tablicę stron – wtedy wszystkie procesy pracują we wspólnej wirtualnej przestrzeni adresowej, przy czym każdy z nich używa innej jej części. Odmiennym podejściem jest utrzymywanie osobnych tablic stron dla każdego procesu oraz dodatkowej na potrzeby samego systemu operacyjnego. W tym modelu każdy proces posiada swoją własną, niezależną przestrzeń adresową. Dwa identyczne adresy logiczne należące do różnych procesów tłumaczone są na inne adresy rzeczywiste, uniemożliwiając tym samym jednemu procesowi modyfikację danych innego.

Zarządca pamięci

Ta część systemu operacyjnego odpowiada za tworzenie i zarządzanie tablicami stron, a także obsługuje przerwanie braku strony generowane przez MMU. W przypadku jego wystąpienia zarządca poszukuje wskazanej strony na dysku twardym (pamięć wymiany), ładuje ją do aktualnie wolnej ramki, uaktualnia tablicę stron i nakazuje MMU ponowne przetłumaczenie adresu. Ładowanie brakujących stron z dysku jest powolnym procesem, dlatego jeśli system dysponuje wystarczającą liczbą ramek, dąży do minimalizacji wystąpień błędów braku strony.

Gdy ilość dostępnej pamięci operacyjnej jest na wyczerpaniu, zarządca może podjąć decyzję o przeniesieniu części stron z ramek na dysk. Do wyznaczenia niepotrzebnych stron stosowany jest algorytm LRU (Least Recently Used), w którym na dysk przenoszone są najdawniej używane strony jako te, których najprawdopodobniej proces będzie potrzebować najpóźniej.

Strony krytyczne

Nie wszystkie strony pamięci mogą być przeniesione do pamięci wymiany. Wśród takich krytycznych stron możemy wyróżnić:

  • procedury obsługi przerwań oparte są na tablicy wskaźników do kodu obsługującego poszczególne rodzaje przerwań. Gdyby strony przechowujące ten kod mogłyby być przenoszone do pamięci wymiany, obsługa przerwań byłaby jeszcze bardziej kłopotliwa, szczególnie że brak strony również sygnalizowany jest przez przerwanie;
  • tablice stron same nie podlegają stronicowaniu;
  • bufory danych, które muszą być dostępne dla innych podzespołów komputera, które przeważnie wykorzystują fizyczne adresowanie;
  • krytyczne fragmenty kodu jądra lub aplikacji, gdzie nie można pozwolić na zbyt długie czasy dostępu do pamięci spowodowane przez brak strony.

Segmentowana pamięć wirtualna

Pamięć wirtualna może być zrealizowana również w oparciu o techniki segmentowania. Wirtualna przestrzeń adresowa aplikacji podzielona jest na bloki zmiennej długości zwane segmentami. Adres logiczny składa się z numeru segmentu oraz przesunięcia w obrębie tego segmentu. Pamięć jest wciąż fizycznie dostępna za pomocą tzw. adresu absolutnego lub liniowego. Do jego otrzymania, procesor odczytuje deskryptor segmentu z tablicy segmentów. Zawiera on flagę informującą, czy dany segment znajduje się aktualnie w pamięci czy nie, adres początku segmentu oraz jego długość. Następnie sprawdza czy przesunięcie adresu mieści się w granicach segmentu. Jeśli segment nie znajduje się w pamięci, generowane jest przerwanie powiadamiające system operacyjny o konieczności jego załadowania. W trakcie wczytywania może okazać się niezbędne przeniesienie innych segmentów na dysk, aby zrobić miejsce dla nowego.

Technikę segmentowanej pamięci wirtualnej wspierał jako dodatkową opcję procesor Intel 80286 będący jednym z przodków wszystkich procesorów stosowanych we współczesnych komputerach PC, jednak nie była ona wykorzystywana w większości systemów operacyjnych.

Możliwe jest połączenie segmentacji pamięci ze stronicowaniem poprzez podzielenie każdego segmentu na strony. W systemach korzystających z tej techniki, np. Multics czy IBM System/38, pamięć wirtualna realizowana jest przez stronicowanie, zaś segmentacja wprowadza dodatkowy mechanizm ochrony. W procesorach IA-32 (Intel 80386 wzwyż) segmenty znajdują się w 32-bitowej liniowej, stronicowanej przestrzeni adresowej: segmenty mogą być przenoszone z/do przestrzeni adresowej, zaś strony w obrębie przestrzeni adresowej mogą być przenoszone z/do pamięci operacyjnej. Korzystają z tego jednak tylko nieliczne systemy – najczęściej stosowane jest wyłącznie stronicowanie pamięci.

Różnica pomiędzy pamięcią stronicowaną a segmentowaną nie polega wyłącznie na podziale pamięci na porcje o stałym i zmiennym rozmiarze. W tego typu systemach segmentacja jest często widoczna dla procesów użytkownika, w przeciwieństwie do przezroczystych stron, które nie wymagają od nich żadnego dodatkowego zaangażowania.

Szamotanie procesów

Mianem szamotania określany jest stan procesu, w którym spędza on więcej czasu na oczekiwaniu na brakujące strony pamięci niż na faktycznym wykonywaniu obliczeń, co znacząco spowalnia jego działanie. Problem szamotania występuje we wszystkich implementacjach i objawia się przy zbyt dużym zapotrzebowaniu na pamięć ze strony procesów przy zbyt małej liczbie wolnych ramek[6]. Problem może być częściowo rozwiązany przez poprawienie jakości programów, lecz na dłuższą metę jedynym skutecznym sposobem jest zainstalowanie większej ilości fizycznej pamięci operacyjnej RAM.

Zobacz też

Przypisy

  1. Andrzej Markowski, Andrzej Rydzewski, Henryk Kruszyński: Leksykon techniki mikrokomputerowej. Warszawa: Wydawnictwo Czasopism i Książek Technicznych NOT-SIGMA, 1989, seria: Mikrokomputery. ISBN 83-85001-28-X.
  2. Windows Version History
  3. „Before memory was virtual”. cs.gmu.edu. [zarchiwizowane z tego adresu (2011-10-05)]., Peter J. Denning, 1997
  4. Opis techniczny komputera ATLAS na stronie WWW Uniwersytetu Manchester. [dostęp 2009-06-14]. [zarchiwizowane z tego adresu (2012-07-28)].
  5. Harvey G. Cragon, Memory Systems and Pipelined Processors, Jones and Bartlett Publishers, s. 113, 1996, ISBN 0-86-720474-5.
  6. William Stallings, Systemy operacyjne. Architektura, funkcjonowanie i projektowanie, wyd. IX, Gliwice: Helion, 2018, s. 400, 401, ISBN 978-83-283-3759-6.

Media użyte na tej stronie

Virtual memory.svg
Autor: Ehamberg, Licencja: CC BY-SA 3.0
Harddisk icon is from Oxygen icons (http://www.oxygen-icons.org/, by-sa 3.0)