Pamięć Wirtualna - Windows


Spis treści


Memory Management

Windows 32 do zarządzania pamięcią wirtualną wykorzystuje Win386 Virtual Memory Manager (VMM). Menedżer pamięci wykorzystuje do tego celu sterowniki urządzeń VxD. Do wymiany stron z pamięcią Windows używa pliku wymiany (swapfile) znajdującego się na dysku (np. Win386.SWP lub tzw. pagefile).

Windows przydziela odpowiednią ilość pamięci wirtualnej w czasie startu systemu. Wielkość ta zależy od fizycznego rozmiaru dostępnej pamięci RAM. Swapfile zmienia swój rozmiar w zależności od pamięciowych potrzeb systemu. Jeśli dysk twardy (gdzie przechowywany jest swap) działa wolno, rozmiar pliku wymiany jest zmniejszana. Jeśli z kolei twardy dysk posiada dużo wolnego miejsca i potrzeba większej ilości pamięci, rozmiar pliku wymiany jest zwiększany.

Przyjrzyjmy się obrazkowi, ukazującemu, jak działa zarządzanie pamięcią w systemie Windows (schemat nie różni się w zasadzie od schematu wykorzystywanego w innych systemach operacyjnych):

pic_Virtual_Memory

Przestrzeń adresowa procesów jest odwzorowywana w katalogach i tablicach stron, pozycje w tych katalogach i tablicach z kolei wskazują na odpowiednie miejsca w pamięci RAM lub w pliku wymiany.

Przestrzeń Adresowa

Adres wirtualny wykorzystywany przez proces nie reprezentuje aktualnej fizycznej lokacji obiektu w pamięci. Zamiast tego, system przechowuje mapę stron dla każdego procesu, która stanowi wewnętrzną strukturę danych wykorzystywaną przy tłumaczeniu adresu wirtualnego na odpowiadający mu adres fizyczny. Za każdym razem kiedy proces odwołuje się do jakiegoś adresu, system tłumaczy adres wirtualny na adres fizyczny.

Przestrzeń wirtualna każdego procesu wynosi najczęściej 4GB. Jednak niektóre systemy z rodziny Windows potrafią obsługiwać przestrzeń adresową 8, 32 lub nawet 64GB (patrz dalej). Poza tym przestrzeń adresowa każdego procesu nie jest jednolita i w zależności od systemu dzieli się na części:


Pamięć Wirtualna w systemie Windows NT

Wprowadzenie

Windows NT obsługuje pamięć wirtualną za pomocą mechanizmu stronicowania dwupoziomowewgo, udostępniając procesom możliwość liniowego adresowania wirtualnego 4 GB-ów pamięci za pomocą 32-bitwego adresu. Rezultatam tego jest przydzielenie każdej aplikacji jej własnej przestrzeni adresowej, którą proces może dowolnie wykorzystać w obrębie pierwszych dwóch gigabajtów i rezerwacja wyższych 2GB-ów przestrzeni adresowej procesu do wykorzystania przez system operacyjny.

pic_nt_vmm_1

Powyższy obrazek ilustruje sposób w jaki każdy proces może zaadresować 4GB za pomocą liniowego adresu wirtualnego. Górna część przestrzeni jest zarezerwowana dla systemu. Do czego to się może przydać? Ponieważ system operacyjny jest ten sam dla wszystkich procesów, te same strony pamięci systemowej są zwykle zmapowane pod te same adresy w każdym procesie, dzięki czemu zwiększa się wydajność systemu.

Można w tym momencie zaznaczyć, że większość systemowych dynamicznie ładowanych bibliotek (DLL) jest lokowane w części adresowej przeznaczonej dla systemu. Jednak Windows umożliwia wykorzystanie dolnego fragmentu przestrzeni do ładowania bibliotek na życzenie użytkownika. Biblioteki zmapowane w dolnym fregmencie przestrzeni adresowej mogą być zmieniane.

Pamięć wirtualna w Windows NT

Windows NT zerwał z segmentową strukturą pamięci zastosowaną w poprzednich wersjach systemu Windows. Bazując na 32-bitowym wirtualnym adresie liniowym jest w stanie operować na procesach adresujących 4GB pamięci. Virtual Memory Manager przejął od procesów gospodarkę pamięcią. Dzięki temu zarządzanie pamięcią dzieje się całkowicie niezależnie od aplikacji w nim działających.

Poprzednie wersje Systemu, jak np. Windows 3.1 musiały przenosić duże segmenty pamięci w inne miejsca tej samej pamięci, celem zwolnienia odpowiedniej ilości ciąglej pamięci, w którą będzie można załadować jakiś kod wykonywalny. Koniecznością było, aby segment wykonywalny znajdował się w pierwszych 640KB pamięci - Windows NT nie ma już takich ograniczeń. Adresowanie pamięci w NT ma niewielki związek z fizycznym położeniem tej pamięci. Dwa jednakowe adresy pamięci wirtualnej mogą się odnosić do dwóch różnych lokalizacji fizycznych. Poza tym przestrzenie adresowe różnych procesów są w zasadzie niezależne, więc procesy nie muszą przejmować się kolizją w lokalizacji pamięci z innymi procesami. Pamięć w NT nie musi stanowić ciągłego obszaru aby przez proces była widziana jako ciągła - zatem nie ma potrzeby przesuwania bloków pamięci, aby zwolnić obszar ciągły.

Windows NT korzysta ze standardowego schematu, wykorzystując proces stronicowania, ze stroną wielkości 4KB. Wszystko co korzysta z pamięci jest zaimplementowane za pomocą tego mechanizmu. VMM korzysta z pamięci wirtualnej wykorzystując dostępną pamięć fizyczną oraz twardy dysk, jako narzędzie służące do gromadzenia stron, które w danym momencie nie są wykorzystywane przez żaden z procesów. NT zapisuje zbędne strony w plikach zwanych 'pagefile'ami. Przez wymianę stron pamięci z dyskiem VMM może czynić strony dostępnymi dla aplikacji na żądanie dostępu do tych stron, przez załadowanie ich z dysku do pamięci. Dzięki temu NT zapewnia dużo większe możliwości zarządzania pamięcią - można wykorzystywać znacznie większą pamięć niż mamy dostępną w danym momencie pamięć fizyczną. Pliki wymiany rosną dynamicznie - jeśli coraz więcej pamięci jest wykorzystywane - coraz większe stają się pliki wymiany.

Adres Wirtualny

Jak już była mowa Windows NT korzysta z 32-bitowego wirtualnego adresu liniowego. Jest on niczym innym poza zakodowaną informacją używaną do znalezienia aktualnego adresu fizycznego, który mu odpowiada. Windows NT dzieli każdy adres wirtualny na trzy grupy: dwie zawierające po 10 bitów i jedną złożoną z 12 bitów.

pic_nt_vmm_2

Katalog stron, tablice stron, ramki stron

Page Directory (katalog stron), Page Tables (tablice stron) i Page Frames (ramki stron) to specjalne struktury, służące do przetłumaczenia adresu wirtualnego na adres fizyczny. Pierwszym krokiem w zamianie adresu wirtualnego jest potraktowanie najwyższych 10 bitów tej liczby jako pierwszego offsetu. Jest on wykorzystywany do ponumerowania 4-bajtowych wartości w stronie pamięci zwanej katalogiem stron. Każdy proces ma swój własny unikalny katalog stron. W rzeczywistości jest on zwykłą storną pamięci, podzieloną na 4-bajtowe wpisy zwane page-directory entries (PDE). 10 bitów adresu wirtualnego jest wystarczającą liczbą bitów do zaadresowania każdego z wpisów w katalogu stron (210 bitów = 1024 możliwe kombinacje co odpowiada 4KB / 4 bajty = 1024 wpisy PDE).

Każdy PDE jest następnie używany do zidentyfikowania innej strony w pamięci, zwanej tablicą stron (za pomocą 20-bitowego adresu, który jest częścią PDE - patrz dalej). Kolejne 10 bitów adresu wirtualnego jest używana do znalezienia odpowiedniego wpisu w tej tablicy stron (jest on dokładnie taką samą 4-bajtową strukturą w tablicy stron zwaną page-table entry (PTE) jaką jest PDE w katalogu stron). PTE identyfikuje stronę w pamięci zwaną ramką (page frame). Pozostałe 12 bitów adresu wirtualnego służy do znalezienia odpowiedniego miejsca (offsetu) w ramce (12 bitów wystarcza na zaadresowanie wszystkich 4096 bajtów na tej stronie.

W związku z tymi trzema warstwami niebezpośredniego adresowania, Windows NT oferuje pamięć wirtualną, unikalną dla każdego procesu i niezależną od pamięci innych procesów oraz dostępnych zasobów fizycznych.

Algorytm tłumaczenia adresu

Tłumaczenie adresu wirtualnego od katalogu stron do ramek jest właściwie wyszukiwaniem w B-drzewie, gdzie katalog stron jest korzeniem, tablice stron są węzłami wewnętrznymi a ramki są liśćmi. Zależność tą pokazuje obrazek:

pic_nt_vmm_3

Katalog stron składa się z 1024 PDE, które odnoszą się do maksymalnie 1024 tablic stron. Każda tablica stron (również złożona z 1024 wpisów PTE) z kolei wskazuje na maksymalnie 1024 ramki w pamięci. Ostatecznie w każdej ramce znajduje się 4096 bajtów reprezentujących właściwe dane. Zbierając wszystko razem otrzymujemy przekształcenie 32-bitowego liniowego adresu wirtualnego na 4GB-ową przestrzeń adresową (1024 * 1024 * 4096).

Można się zastanowić jak duża jest struktura potrzebna do reprezentacji pełnych 4GB. Żeby zaadresować wszystkie ramki w pamięci wymagane jest istnienie jednego katalogu stron i wszystkich 1024 tablic stron. Biorąc pod uwagę rozmiar strony - 4KB do reprezentacji tej struktury potrzeba 4MB pamięci ( [1024 page tables + 1 page directory] * 4096 bytes/page). Wydaje się to dość dużą ceną, ale 4MB to znacznie mniej niż 0.1 procenta całej 4GB-owej przestrzeni adresowej. Poza tym za każdym razem gdy szukamy odpowiedniej ramki musimy przejrzeć tylko 8KB - katalog stron i jedną tablicę stron. Poza tym nie cała struktura rezyduje w systemie - odpowiednie jej fragmenty są tworzone w miarę potrzeby, więc tablice stron nie są tworzone zanim adresy, których one używają do tłumaczenia nie są potrzebne.

A jak dokładnie wygłąda algorytm tłumaczenia adresu?

  1. Za pomocą liczby utworzonej z 10 najwyższych bitów przesuniętych w lewo o dwie pozycje znajdź odpowiednie miejsce w katalogu stron z dokładnością do 4 bajtów (adres katalogu stron jest przechowywany w jednym z rejestrów - np. dla x86 jest to rejestr CR3)
  2. Znaleziony 4-bajtowy wpis (PDE) wskazuje na poszukiwaną tablicę stron
  3. Za pomocą liczby utworzonej z 10 środkowych bitów przesuniętych o dwie pozycje w lewo wyszukaj odpowiedniego miejsca w znalezionej właśnie tablicy stron z dokładnością 4-bajtową
  4. Znaleziony 4-bajtowy wpis (PTE) wskazuje na poszukiwaną ramkę w pamięci
  5. Za pomocą najniższych 12 bitów znajdź w ramce poszukiwany bajt pamięci

Dokładniejszy wygląd wpisów w katalogu i tablicach stron będzie omówiony później. Tak cały proces wygląda na obrazku:

pic_nt_vmm_4

Pamięć zarezerwowana i potwierdzona

Alokacja pamięci w Windows NT jest procesem dwustopniowym. Najpierw są rezerwowane pewne adresy przestrzeni wirtualnej procesu, potem są one potwierdzane. Proces rezerwacji jest po prostu powiedzeniem VMM, żeby zarezerwował blok stron pamięci wirtualnej, aby dzięki temu zaspokoić późniejsze żądania pamięciowe procesu. VMM nie dokonuje żadnych zmian w pamięci w chwili rezerwacji, ponieważ rezerwowanie nie używa aktualnej pamięci. Kiedy proces zechce wykorzystać pamięć, którą sobie zarezerwował musi ją najpierw potwierdzić. Próba dostępu do pamięci zarezerwowanej, ale nie potwierdzonej zwykle kończy się zabronieniem dostępu. Kiedy proces chce potwierdzić pewne adresy, VMM upewnia się, czy proces ma wymagane Quota pamięciowe żeby to zrobić. VMM sprawdza też czy jest dostępna wymagana ilość pamięci (fizycznej oraz dyskowej w plikach wymiany).

Jest wiele sytuacji, w których aplikacje chcą zarezerwować duży blok przestrzeni adresowej do przyszłego wykorzystania (przechowywania danych w ciągłym obszarza pamięci, aby łatwo nimi zarządzać), ale zdarza się że aplikacje nie korzystają całego zarezerwowanego obszaru. Jest możliwe jednoczesne zarezerwowanie i potwierdzenie pamięci i jest to najczęstszy sposób alokowania pamięci.

Oto kilka przykładów, w których korzysta się z rezerwacji pamięci:

Kiedy proces rezerwuje pamięć, musi wyspecyfikować jej rozmiar, ale może też podać początkowy adres wirtualny, od którego przestrzeń ma być rezerwowana jak też prawa dostępu nakładane na dany obszar pamięci. NT wykorzystuje do tego bity w PTE, które są ustawiane przez MMU i oznaczają prawa do czytania lub pisania na stronie oraz czy kod na stronie jest wykonywalny. Jeśli np. bity w PTE definiują stronę jako tylko do odczytu (read-only) a proces próbuje do niej pisać - wtedy MMU generuje page fault i systemowy page fault handler zabrania procesowi dostępu do strony.

W Windows NT istnieje różnica pomiędzy pamięcią i przestrzenią wirtualną. Mimo iż każdy proces posiada 4GB-ową przestrzeń adresową rzadko się zdarza by proces potrzebował ilości pamięci zbliżonej do rozmiaru jego przestrzeni adresowej. W związku z tymi różnicami VMM musi przechowywać dane o adresach używanych i nieużywanych przez proces. W związku z tym NT przechowuje strukturę reprezentującą cała pamięć fizyczną oraz strukturę reprezentująca przestrzeń adresową każdego procesu.

System przechowuje listy zarezerwowanych lub potwierdzonych zakresów adresowych w przestrzeni adresowej procesu w drzewiastej strukturze, jak to pokazuje obrazek:

pic_nt_vmm_04

Każdy węzeł wewnątrz drzewa reprezentuje pewien zakres stron, które mają podobną charakterystykę, również pod względem praw dostępu i ststutu potwierdzonej pamięci. Drzewo to jest binarnym drzewem typu splay, żeby zminimalizować jego wysokość. Węzły drzewa są nazywane deskryptorami wirtualnego adresu (Virtual Address Descryptors - VADs), a tzw. Process Conrtol Block przechowuje korzeń tego drzewa. Dzięki temu, kiedy proces dokonuje rezerwacji lub potwierdzenia pamięci, VMM może szybko sprawdzić, gdzie w przestrzeni adresowej są wolne bloki itp.

Mapowanie plików

Potężną funkcją menedżera pamięci jest pozwalanie programom na mapowanie plików do ich wirtualnych przestrzeni adresowych. Mapowanie to odbywa się w dwóch krokach. W pierwszym program tworzy obiekt zwany Section Object, w celu opisania pliku, który ma zostać zmapowany. Section Object przechowuje informacje o nazwie pliku, jego rozmiarze oraz częściach, które już zostały zmapowane.

W drugiej fazie program mapuje wszystki części pliku w przestrzeni adresowej procesu. Proces decyduje od którego offsetu pliku należy zacząć mapowanie i jak duży jego fragment należy zmapować. Dodatkowo proces określa prawa ochrony (read-only / read-write) danego fragmentu pliku. Od momentu zmapowania obrazu pliku proces może z niego korzystać po prostu przez czytanie i pisanie do adresów obrazu w przestrzeni adresowej procesu. VMM wspólpracuje z systemem plików, aby zapewnić widoczność wszystkich zmian dokonanych przez proces w pliku.

Mapowanie plików reprezentuje jeszcze jeden przykład na rezerwowanie pewnego zakresu pamięci do wykorzystania w przyszłości. Podczas pierwszego kroku mapowania, rezerwowana jest przestrzeń wielkości całego pliku. Dopiero druga faza specyfikuje, które fragmenty plkiu należy zmapować. Można sobie wyobrazić sytuację w której tylko niewielkie fragmenty (obrazy) pliku będą wczytywane do zarezerwowanej pamięci na żądanie procesu.

Inną korzyścią wynikającą z rezerwowania pamięci jest to, że adresy są z zasady ciągłym obszarem przestrzeni. Windows NT korzysta z tego do mapowania kodu wykonywalnego każdej aplikacji pod określone adresy. Ponieważ kod programu jest widziany jako ciągły jest on dzięki temu w pamięci reprezentowany jako obszar spójny. Oczywiście nie jest konieczne wczytywanie od razu całego kodu do pamięci - kolejne jego fragmenty są wczytywane na żądanie.

Poniższa tabelka pokazuje w jakim stanie może znajdować się każda strona w pamięci i co to oznacza:

STATE DESCRIPTION
Free The page is neither committed nor reserved. The page is not accessible to the process. It is available to be committed, reserved, or simultaneously reserved and committed. Attempting to read from or write to a free page results in an access violation exception.
Reserved The page has been reserved for future use. The range of addresses cannot be used by other allocation functions. The page is not accessible and has no physical storage associated with it. It is available to be committed.
Commited Physical storage is allocated for the page, and access is controlled by a memory protection option. The system initializes and loads each committed page into physical memory only during the first attempt to read or write to that page. When the process terminates, the system releases the storage for committed pages.

Bufor TLB

Rozważając całą pracę wykonywaną przez Windows NT przy próbie odtworzenia adresu fizycznego strony można odnieść wrażenie, że jest to proces nieefektywny. Żeby przetłumaczyć pojedynczy sdres wirtualny VMM musi przejrzeć trzy strony w pamięci. Dlatego Windows NT używa dodatkowego mechanizmu, który działa równolegle z tłumaczeniem adresu opisanym powyżej.

System wykorzystuje Translation Lookaside Buffer (TLB) - mechanizm sprzętowy wspomagający tłumaczenie adresu. TLB zwykle realizowany jako wewnętrzna pamięć podręczna cache, jest niczym oprócz 64-kilobajtowego bufora, który jest używany przez sprzęt do uzyskiwania szybkich dostępów do odpowiednich adresów pamięci fizycznej. Bufor ten jest wykorzystywany do przechowywania ostatnio używanych adresów wirtualnych i sprzężonych z nimi adresów fizycznych. Dzięki temu VMM ma możliwość przejścia od adresu wirtualnego bezpośrednio do położenia fizycznego strony, bez konieczności czasochłonnego tłumaczenia tego adresu za pomocą katalogu stron i tablic stron.

TLB - jako komponent sprzętowy ma specjalny mechanizm wspomagający jego przeszukiwanie. Wyszukiwanie w TLB może być przeprowadzone współbieżnie z tłumaczeniem adresu za pomocą struktury stron, a ponieważ jest on dużo szybszy w porównaniu ze zwykłym mechanizmem, możliwe jest znaczne skróceni czasu dostępu do poszukiwanej strony. Właściwie można założyć że wyszukanie odpowiedniego wpisu w TLB trwa jeden krok. Jedynym ograniczeniem tego bufora jest ilość wpisów, którą jest w stanie przechowywać - wielkość TLB pozwala na umieszczenie w nim 32 tylko wpisów. TLB prezentuje się mniej więcej następująco:

pic_nt_vmm_tlb

Każdy wpis w TLB składa się z wirtualnego adresu oraz sprzężonego z nim wpisu PTE, który dokładnie identyfikuje ramke pamięci. Istnieje mechanizm zabezpieczający przed zbędną redundancją wpisów w buforze (nie ma dwóch identycznych wpisów). Za każdym razem kiedy adres wirtualny jest tłumaczony software'owo i odnosi się do nowej strony jest on dodawany do TLB. Kiedy TLB jest pełny wpisy do nowych stron są do niego dodawane zgodnie z zasadą, że do usunięcia przeznacza się najdawniej używane (Last Recently Used).

PTE (Page Table Entry)

Tłumaczenie adresu wirtualnego opisane wcześniej wykorzystywało katalog stron i tablice stron. Jedna rzecz nie została jednak dokładnie opisana - nie opisano struktury każdego wpisu w tablicy stron. Strony zarezerwowane lub potwierdzone w pamięci rezydują jako strony w pamięci RAM lub zbuforowane na dysku w postaci 'pagefile'i. PTE identyfikuje położenie strony, jech prawa ochrony, jej plik wymiany oraz status strony. Pokazuje to następujący obrazek:

pic_nt_vmm_5

Poszczególne bity mają następujące znaczenie:

Page Faults

Kiedy jakiś proces odwołuje się do strony, która nie jest obecna w pamięci (jej PTE jest ustawiony jako nie Present) MMU podnosi wyjątek page-fault. Wyjątek ten jest obsługiwany natychmiastowo przez wczytanie brakującej strony do pamięci i wznowienie instrukcji, która wygenerowała wyjątek braku strony. Jest to proces w miarę szybki, ale nagromadzenie wyjątków page-fault może dość znacznie wpłynąć na obniżenie wydajności.

Nawet translacja pojedynczego adresu może wywołać aż trzy wyjątki braku strony. Wynika to z faktu, że wyszukiwanie strony polega na przeglądaniu katalogu stron, tablicy stron i ramki, z których żadna może nie być obecna w pamięci i generować page-fault przy próbie odwołania się do niej. Jest to jedna z sytuacji, w których TLB może znacząco poprawić wydajność systemu przez unikanie page-fault'ów, kiedy następują odwołania do katalogu i tablicy stron nieobecnych w pamięci, ale obecnych w TLB. Oczywiście sytuacje, w których występują 3 wyjątki mogą przeplatać się z innymi - pośrednie są również możliwe - kiedy page-fault zostanie podniesiony raz lub dwa razy.

Pamięć Dzielona

Ponieważ każdy proces ma swój własny katalog stron odrębność przestrzeni adresowej każdego procesu jest bardzo duża. Ma to swoje dobre i złe strony. Chroni to procesy przed działaniem destruktywnym innych procesów. Jednak, ponieważ dwa procesy mogą używać tego samego adresu do określenia różnych lokacji w pamięci, procesy nie mogą przekazywac sobie adresów. To czyni mechanizm współdzielenia pamięci dość skomplikowanym do implementacji.

W systemie NT problem ten rozwiązano w sposób trikowy. Ponieważ nie ma fizycznych barier nie pozwalających trzymać w tablicach stron różnych procesów identycznych wpisów PTE, odnoszących się do tej samej strony - Windows NT wspiera pamięć dzieloną właśnie w ten sposób. To jednak nie rozwiązuje wszystkiego. Co się stanie, gdy status dzielonej przez cztery procesy strony ulegnie zmianie (np. jeden z procesów zacznie do niej pisać). Wtedy system będzie musiał uaktualnić cztery wpisy PTE, po jednym dla każdego z czterech procesów. Takie zachowanie byłoby całkiem kosztowne, a biorąc pod uwagę, że mowa tu o tylko jednej stronie lepiej nie myśleć jak drastycznie spadłaby wydajność gdyby takich stron było dużo. Poza tym nie istnieje sposób na określenie wszystkich referencji z tablic stron do danej strony. NT wychodzi naprzeciwko temu problemowi. Zamiast przetrzymywać wielokrotne wskażniki PTE do współdzielonej strony problem rozwiązano dodając dodatkową warstwę stron (dodatkową tablicę stron) na drodze między tablicami stron a dzieloną stroną - ta dodana struktura nosi nazwę tzw. Prototype PTE. P_PTE jest właściwie wyłącznie referencją na właściwą stronę, którą procesy między sobą współdzielą.
Każdy wpis PTE w tablicach ston procesów wskazuje na stronę pośrednią Prototype PTE, która dopiero wskazuje na właściwą stronę współdzieloną. P_PTE jest również 32-bitowe, dzięki czemu wskazuje dokładnie na dzieloną ramkę w pamięci. Zależność między procesami a pamięcią dzieloną ilustruje obrazek:

pic_nt_vmm_6

Mechanizm współdzielenia stron przychodzi ze swoim własnym narzutem wydajnościowym. Prototype PTE jest zaimplementowane jako zasób globalny, zmapowany do górnego fragmentu przestrzeni adresowej każdego z procesów. Maksymalnie 8MB jest przez system zarezerwowane do wykorzystania na alokację stron P_PTE. Na szczęście P_PTE są alokowane dynamicznie w miarę potrzeb systemu, więc pamięć nie jest niepotrzebnie tracona. Największy spadek wydajności jest jednak związany z wyjątkami page-fault, gdy następują próby odwołania do stron wspóldzielonych, które nie rezydują w pamięci. Dodatkowa warstwa stron może zwiększać liczbę maksymalnych page-fault'ów z trzech do czterech.

Mechanizm Copy-on-Write

VMM potrafi wykorzystywać ciekawą optymalizację pamięci dzielonej zwaną copy-on-write. Jest wiele praktycznych sytuacji, w których proces może chcieć używać tych samych danych co inny proces, ale nie chce widzieć żadnych modyfikacji, których dokonuje inny proces jak też modyfikacje których sam dokonuje pragnie zachować tylko dla siebie. Na przykład dwa procesy startują tą smą aplikację ale jeden z nich modyfikuje dane w obrazie, drugi proces nie powinien widzieć żadnych modyfikacji. Najprostszą metodą zaspokojenia takich potrzeb procesów jest trzymanie w pamięci jednocześnie wielu instancji tych samych danych - jednak powoduje to znaczne straty pamięci.

Zamiast tego VMM zaznacza strony fizyczne współdzielonej pamięci jako read-only oraz zaznacza w wewnętrznej strukturze danych (patrz dalej), że strony mają charakter copy-on-write. Kiedy jakiś proces będzie próbował dokonać modyfikacji strony copy-on-write, zostanie wygenerowany wyjątek page fault, ponieważ strona jest tylko do odczytu. VMM sprawdzi w wewnętrznej strukturze reprezentującej pamięć, że dana strona jest typu cpy-on-write, a następnie skopiuje jej zawartość do nowej strony, która będzie prywatną stroną procesu.

pic_nt_vmm_cow1 pic_nt_vmm_cow2

Na powyższych obrazkach dwa procesy dzielą trzy strony copy-on-write. W chwili, gdy pierwszy proces zaczyna pisać do jednej ze stron, dostaje on swoją prywatną kopię strony, podczas gdy proces drugi wciąż wskazuje na oryginalną stronę.

UWAGA: NT używa mechanizmu copy-on-write głównie dla wykonywalnych fragmentów kodu. Systemy POSIX-owe równie często używają tego mechanizmu podczas forkowania (nie następuje wtedy kopiowanie całego kodu tylko jego współdzielenie na zasadach copy-on-write do czasu gdy jeden z procesów nie będzie modyfikował zawartości wsółdzielonych stron).

Zarządzanie pamięcią - VMM

Virtual Memory Manager w systemie NT jest osobnym procesem odpowiedzialnym za zarządzanie pamięcią fizyczną jak też pagefile'ami. Stanowi on wykonywalny fragment systemu pracujący w trybie jądra. W związku ze szczególną rolą jaką VMM pełni w systemie rezyduje on w niewielkiej przestrzeni pamięci zwanej non-paged pool, który nigdy nie jest buforowany na dysku.

Największy wpływ jaki posiada Memory Menager na system i wydajność poszczególnych aplikacji jest allokacja pamięci fizycznej da każdego aktywnego procesu. Rozmiar pamięci, którą VMM przyłącza do procesu jest nazywana jego zbiorem roboczym (Working Set). Każdy proces ma swój prywatny zbiór roboczy. Specjalny Working Set, zwany systemowym, jest fizyczną pamięcią, która jest przydzielana systemowi, czyli wszystkim aplikacjom systemu, sterownikom urządzeń oraz menedżerowi pamięci podręcznej (Cache Manager). Jeśli zbiór roboczy procesu jest zbyt mały, proces powoduje wiele wyjątków 'page-fault', kiedy próbuje się odwoływać do stron, które są nieobecne w pamięci, ale należą do pamięci procesu i są zapisane w pliku wymiany. Za każdym razem, kiedy będzie zgłoszony page fault, VM Manager będzie musiał przeprowadzić operacje dyskowe celem przywrócenia strony do pamięci. Jeśli zbiór roboczy jest zbyt duży, proces będzie rzadko powodował przerwanie braku strony, ale przydzielona mu pamięć fizyczna będzie przechowywać dane, do których rzadko będzie się odwływał, przez co będzie się niepotrzebnie ograniczać ilość wolnej pamięci, która mogłaby zostać wykorzystane przez inne procesy. Dlatego VMM musi zachować odpowiednie proporcje w zarządzaniu pamięcią każdego procesu.

Windows NT stosuje dwie taktyki gospodarowania pamięcią: the page fetch policy oraz the page replacement policy. The page fetch policy służy do dostarczania procesowi potrzebnych stron. NT używa najbardziej popularnej pfp - tzw demand paing (strona na żądanie). Demand paging polega na tym, że dane potrzebne procesowi są mu dostarczane (page-in) gdy ten próbuje się do nich odwołać. Inna PFP - prefetching (przewidywanie przenoszenia) wymaga od systemu przewidywania, które strony będą potrzebne procesowi i dostardczanie ich zanim proces się do nich odwoła. Prefetching może znacznie usprawnić wydajność jednej aplikacji kosztem innych, ponieważ VMM będzie ładował do pamięci wiele stron (marnując miejsce), które nie są wykorzystywane przez proces, aby w trakcie odwołania do konkretnej z nich znajdowała się ona już w pamięci fizycznej. NT wykorzystuje w praktyce zmodyfikowanej wersji demand paging - tzw. clustered demand paging (blokowe stronicowanie na żądanie). Zamiast dostarczać procesowi pojedynczej strony, do której w danym momencie się odwoła, do pamięci jest ładowana ta strona, wraz z sąsiednimi (istnieje duże prawdopodobieństwo, ze proces odwoła się do strony, kora po niej następuje lub do tej poprzedzającej). Strony pamięci, które są dostarczane są nazywane klastrem (blokiem ang. cluster). W NT ilość stron w klastrze może oscylować w granicach 0 - 7, w zależności od ilości fizycznej pamięci dostępnej systemowi oraz od rodzaju ładowanej pamięci (kod wykonywalny, dane).

The page replacement policy jest strategią zarządzania zbiorem roboczym, której celem jest wybranie stron przeznaczonych do usunięcia z tego zbioru. VMM musi z pamięci usunąć strony za każdym razem, gdy pamięć jest przepełniona nie używnymi stronami, a jest potrzebna do załadowania stron, które są właśnie procesowi potrzebne. Istnieją dwie metody usuwania stron z pamięci; globalna i lokalna. W globalnej PRP Memory Manager traktuje wszystkie strony, jako potencjalnych kandydatów do usunięcia, niezależnie od tego do których procesów strony te należą. W lokalnej PRP kandytadami do usunięcia są tylko strony przynależne do zbioru roboczego procesu, który próbuje dostać się do strony nieobecnej w pamięci. Globalne usuwanie stron może w krótkim czasie zwolnić znaczną ilość pamięci, jednak tym samym inne procesu zostaną pozbawione własnej pamięci, do której być może będą się odwoływać. NT stosuje strategię mieszaną w PRP. Zwykle jest to lokalne usuwanie, gdyż najpierw usuwa się strony należące do procesu, który zgłosił żądanie. Jednak stosowana jest również metoda globalna, która usuwa strony ze zbiorów roboczych innych procesów, jeśli ich zapotrzebowanie na pamięć nie jest duże.

PRP jest również charakteryzowana według strategi doboru stron, które są z pamięci usuwane (niezależnie czy chodzi o lokalną czy globalną politykę). Jedną ze strategii jest wybieranie do usunięcia tych stron, które zostały jako pierwsze dodane do zbioru roboczego procesu (FIFO - First In First Out). Algorytmem, który cechuje się znacznie większą wydajnością aplikacji jest usuwanie najdawniej używanych stron (Last Recently Used - LRU). Konieczne w tym przypadku jest informowanie menedżera pamięci przez MMU o stroach, które najdłużej pozostały nieużywane. LRU wymienia w pierwszej kolejności strony do których nie było odwołań przez najdłuższy okres czasu. W architekturze x86 Windows NT używa mechanizmu zegarowego, który jest prostą formą wymiany LRU, bazującą na ograniczonym śledzeniu dostępów do stron. Za każdym razem kiedy proces odwołuje się do jakiejś strony, MMU ustawia flagę Accesed (na 1) we wpisach PTE wskazujących na tą stronę. Jeśli flaga Accesed nie jest ustawiona dla pewnej strony, VMM wie, że żaden proces nie odwołał się do strony odkąd VMM po raz ostatni operował na wpisie PTE wskazującym na nią.

Zbiór roboczy każdego procesu, wliczając w to systemowy zbiór roboczy, ma określony rozmiar minimalny, rozmiar bieżący oraz rozmiar maksymalny. Na przeciętnym systemie NT, wyposażonym w 64MB pamięci fizycznej, standardowy minimalny rozmiar zbioru roboczego wynosi 200KB, a standardowy rozmiar maksymalny wynosi 1.4MB (limit ten może zostać przekroczony przez proces posiadający specjalne przywileje). Na starcie każdy proces generuje wiele page-fault'ów, jako efekt odwołań do danych występujących jako pamięć zmapowana (najczęściej obraz wykonywalny), która musi zostać załadowana do pamięci fizycznej. VMM pozwala zbiorowi roboczemu procesu rosnąć aż do osiągnięcia rozmiaru maksymalnego, a kiedy rozmiar osiągnie maksimum VMM pozwala na dodatkowe rozszerzenie Working Set'a ale tylko jeśli wiele wolnych stron jest dostępnych w pamięci. Jeśli wolnej pamięci brakuje, VMM rozpoczyna proces zarządzania zbiorem roboczym procesu zgodnie z zasadami opisanymi powyżej. Strony ze zbioru roboczego procesu są połączone w listę, którą skanuje VMM. Na procesorach x86 jeśli VMM odnajdzie stronę z ustawioną flagą Accessed, czyści tą flagę i przechodzi do następnej strony. Do usunięcia są typowane strony na których wyczyszczony jest bit Accessed. Oznacza to, że strona taka nie została użyta od ostatniego do niej dostępu przez VMM. Unika się usuwania stron, do których odwołał się proces od czasu ostatniego jej skanowania przez VMM - istnieje duże prawdopodobieństwo, że proces będzie się do nich odwoływał w najbliższym czasie. Proces skanowania wykonuje się cyklicznie, przechodząc za każdym razem cała listę.

Page-Frame Database

NT organizuje swoją pamięć jako listę stron wielkości 4KB. VMM używa prywatnej struktury danych do zarządzania statutem każdej ze stron fizycznych w systemie. Struktura ta jest zwana Page-Frame Database (Bazą Danych Ramek). Każdy wpis w PFD ma swój odpowiednik w stronie fizycznej w pamięci. W tych wpisach przechowywane są informacje o statucie danych trzymanych w stronach, do których wpisy te się odnoszą. Strona może przyjmować jeden z następujących ośmiu statusów:

STATUS OPIS
Valid = Active Strona jest używana przez jeden z aktywnych procesów. Jej wpis PTE jest ustawiony na Valid.
Modified Strona została zmieniona (zapisana), ale jeszcze nie zapisana na dysku. Jej PTE jest zaznaczone jako Invalid in Transition.
Standby Strona usunięta ze zbioru roboczego procesu. Jej PTE jest ustawione na Invalid in Transition.
Free Strona nie będąca w użyciu i nie posiadająca swojego wpisu PTE (zostały już usunięte wszystkie referencje z procesu do niej). Zanim zostanie ponownie przyłączona do któregoś z procesów powinna zostać wyzerowana (w takim stanie może zostać wykorzystana tylko do odczytu).
Zeroed Wolna strona przygotowana do użycia - można ją bezpośrednio przyłączyć do procesu.
Modified No Write Strona wykorzystywana przez system plików - np. do przechowywania metadanych. Strona została już usunięta ze zbioru roboczego procesu, ale system plików zaznaczył ją jako używaną. VMM czeka na zgłoszenie zakończenia jej obsługi i nie może jej automatycznie zapisać na dysku nawet jeśli została zmieniona dopóki nie zwolni jej system plików.
Transition Strona w stanie przejściowym. Jest zaznaczona jako Invalid i nie występuje na żadnej liście stron (zwykle w czasie operacji dyskowych, np, buforowania strony w pliku wymiany).
Bad Strona generuje błąd sprzętowy i nie będzie się już nigdy nadawać do użytku.

PFD kojarzy ze sobą strony których status jest taki sam i łączy je w listę wewnątrz bazy. Dzięki temu może w łatwy sposób odnaleźć odpowiednią ilość stron o danym statusie (np. wolnych). Schemat PFD pokazany jest na rysunku:

pic_nt_vmm_7

Przyjrzyjmy się teraz zmianom stanu stron, które mogą zachodzić wewnątrz systemu NT. Ilustruje je poniższy rysunek:

pic_nt_vmm_pfd

Zacznijmy od ston w stanie 'Valid'. Strony takie są aktualnie częścią jakiegoś zbioru roboczego. Strony 'Valid' mogą być stronami Dirty (gdy któryś proces do nich pisał, ale zmieniona zawartość nie została zapisana na dysku - bit Dirty jest ustawiany gdy proces pisze do strony) lub Clean (czyli nie zmienionymi - bit Dirty nie ustawiony).

Kiedy strona 'Valid' jest usuwana ze zbioru roboczgo może zostać przeniesiona do jednej z trzech list. Jeśli strona jest Clean, jest dodawana do listy 'Standby', jeśli jest Dirty najczęściej jest przenoszona do listy 'Modified'. W niektórych przypadkach, kiedy system plików operuje na stronie, przenosi się ona na listę stron 'Modified No Write'.

Strona z listy 'Modified' przenoszona jest na listę 'Standby', ale wcześniej jej zawartość musi zostać zapisana na dysku. Strona z listy 'Modified No Write' jest przenoszonana listę 'Standby' kiedy system plików poinformuje VMM, żeby tem przeniósł stronę.

Strona z listy 'Standby' jest przenoszona na listę 'Free', kiedy proces który był właścicielem strony (miał ją w swoim zbiorze roboczym) zwolni pamięć wirtualną skojarzoną z daną stroną lub zostanie zabity. Istnieje jeszcze jedna możliwość - kiedy strona zostanie przeniesiona ze zbioru roboczego procesu na listę 'Standby', 'Modified' lub 'Modified No Write' i proces zażąda dostępu do strony zanim VMM skojarzy daną stronę z innym procesem VMM przywraca daną stronę do zbioru roboczego procesu, do którego wcześniej należała. Jest to tzw. soft-page faulting - przywracanie stron procesowi.

Strony z listy 'Free' są przenoszone na listę 'Zeroed' po tym jak specjalny wątek wyczyści (wyzeruje) ich zawartość.

Kiedy proces zażąda strony i VMM sprawdzi, że proces nie przekroczył maksymalnego rozmiaru swojego zbioru roboczego strony z listy 'Zeroed' są dodawane do zbioru roboczego procesu. Jeśli lista 'Zeroed' jest pusta, sprawdzana jest lista 'Free', po niej lista 'Standby'. Jeśli wszystkie te listy są puste VMM czeka aż pojawią się wolne strony i przyłącza je do Working Set procesu.

Strony znajdujące się na liście 'Bad' są stronami błędnymi, które nie biorą udziału w dalszym działaniu systemu (np. powodowały błąd hardware'owy).

UWAGA: Konieczność zerowania stron przed ponownym użyciem wynika ze standardów bezpieczeństwa.


Intel PAE

PAE (Physical Address Extention) - Intelowska metoda adresowania pamięci została po raz pierwszy zaimplementowana w procesorze Intel Pentium Pro i obecnie jest szeroko stosowana we współczesnych systemach operacyjnych. PAE umożliwia zaadresowanie do 64GB pamięci za pomocą 32-bitowego wirtualnego adresu liniowego, przy wykorzystaniu 4KB-owej lub 2MB wielkości stony.

Aby cała operacja była możliwa, wpisy w katalogach stron i tablicach stron zostały rozszerzone do 8 bajtów (poprzednio 4 bajty). Dzięki temu adres bazowy katalogu stron i ramek może być rozszerzony do 24 bitów (z 20 bitów). Właśnie stąd biorą się dodatkowe 4 bity potrzebne do adresowania pełnych 64GB (236 bitów) fizycznego adresu.

Algorytm wyznaczania tego adresu jest również nieco inny od opisywanego powyżej. Adres liniowy pozostał 32-bitowy, ale zmienił się trochę jego podział. W przypadku PAE wygląda to następująco (odpowiednio dla 2MB i 4KB wielkości strony):

Strona 2MB:

Strona 4KB:

Algorytm stronicowania trójpoziomowego

  1. Odczytujemy adres odpowiedniego katalogu stron z globalnego wskaźnika na katalogi stron na podstawie zawartości rejestru CR3 i bitów 30-31 adresu liniowego.
  2. W zależności od rozmiaru strony:
  3. Do otrzymanego adresu fizycznego dodajemy przesunięcie (bity 0-11 lub 0-20 w zależności od rozmiaru strony.

Tak ten proces wygląda na obrazku:

pic_i586_paging

Jak Intelowskie rozszerzenie ma się do rodziny systemów Windows?
Niektóre Windowsy mają możliwość wykorzystania tego mechanizmu:

Windows Support
Windows 2000 Advanced Server
Windows .NET Advanced Server
8 processors and 32 GB RAM
Windows 2000 Datacenter Server 32 processors and 32 GB RAM (support for 64 GB was not offered because of a lack of systems for testing)
Windows .NET Datacenter Server 32 processors and 64 GB RAM (based on availability of systems for testing)

Autor: Piotr Jędrzejewski