27 KiB
Pytanie 10: Zarządzanie pamięcią - stronicowanie i segmentacja
Pytanie
"Scharakteryzować problemy i mechanizmy zarządzania pamięcią. Porównać cechy i przeznaczenie mechanizmów stronicowania i segmentacji."
Przedmiot: SOI (Systemy Operacyjne)
📚 Odpowiedź główna
Wprowadzenie
Zarządzanie pamięcią to jeden z kluczowych zadań systemu operacyjnego:
- Przydzielanie pamięci procesom
- Ochrona pamięci między procesami
- Efektywne wykorzystanie ograniczonego zasobu
- Abstrakcja (programista nie musi znać fizycznych adresów)
1. Problemy zarządzania pamięcią
1.1 Fragmentacja
Fragmentacja zewnętrzna (External Fragmentation)
┌─────────────────────────────────────────────────────────────────┐
│ Pamięć fizyczna: │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │PROC│ │FREE│ │PROC│ │FREE│ │PROC│ │FREE│ │PROC│ │
│ │ A │ │ 2K │ │ B │ │ 3K │ │ C │ │ 1K │ │ D │ │
│ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ │
│ │
│ Suma wolnej pamięci: 6K │
│ Ale nie można przydzielić bloku 5K! (fragmentacja) │
└─────────────────────────────────────────────────────────────────┘
Problem: Wolna pamięć jest rozproszona w małych, nieciągłych blokach.
Fragmentacja wewnętrzna (Internal Fragmentation)
┌─────────────────────────────────────────────────────────────────┐
│ Przydzielono blok 4KB, proces potrzebuje 3.5KB: │
│ ┌────────────────────────────────────────┐ │
│ │ WYKORZYSTANE (3.5KB) │ ZMARNOWANE (0.5KB) │ │
│ └────────────────────────────────────────┘ │
│ ↑ │
│ Fragmentacja wewnętrzna │
└─────────────────────────────────────────────────────────────────┘
Problem: Przydzielony blok jest większy niż potrzeba.
1.2 Ochrona pamięci
- Proces A nie może czytać/pisać pamięci procesu B
- Jądro chronione przed aplikacjami użytkownika
- Mechanizmy: rejestry bazowy/graniczny, bity ochrony, ringi
1.3 Relokacja
Problem: Program kompilowany z założeniem konkretnych adresów musi działać pod różnymi adresami.
Rozwiązania:
- Relokacja statyczna (loader)
- Relokacja dynamiczna (MMU - Memory Management Unit)
1.4 Współdzielenie
- Biblioteki współdzielone (DLL, .so)
- Pamięć współdzielona między procesami
- Copy-on-Write (COW)
1.5 Ograniczona pamięć fizyczna
- Więcej procesów niż RAM
- Rozwiązanie: pamięć wirtualna + swap
2. Mechanizmy zarządzania pamięcią
2.1 Partycjonowanie stałe (Fixed Partitioning)
┌────────────────────────────────────────────────────────────────┐
│ Pamięć podzielona na stałe partycje: │
│ ┌──────────┬──────────┬──────────┬──────────┐ │
│ │ Partycja │ Partycja │ Partycja │ Partycja │ │
│ │ 1MB │ 2MB │ 4MB │ 8MB │ │
│ └──────────┴──────────┴──────────┴──────────┘ │
│ │
│ Zalety: Proste, brak fragmentacji zewnętrznej │
│ Wady: Fragmentacja wewnętrzna, maks. rozmiar procesu ograniczony│
└────────────────────────────────────────────────────────────────┘
2.2 Partycjonowanie dynamiczne (Dynamic Partitioning)
┌────────────────────────────────────────────────────────────────┐
│ Partycje tworzone według potrzeb: │
│ ┌─────┬───────────┬────────┬─────────────────────────────┐ │
│ │ P1 │ P2 │ P3 │ WOLNA │ │
│ │ 3MB │ 5MB │ 2MB │ 10MB │ │
│ └─────┴───────────┴────────┴─────────────────────────────┘ │
│ │
│ Zalety: Brak fragmentacji wewnętrznej, elastyczność │
│ Wady: Fragmentacja zewnętrzna! │
└────────────────────────────────────────────────────────────────┘
Algorytmy przydziału:
| Algorytm | Opis | Zalety | Wady |
|---|---|---|---|
| First Fit | Pierwszy wystarczający blok | Szybki | Fragmentacja na początku |
| Best Fit | Najmniejszy wystarczający | Oszczędza duże bloki | Wiele małych fragmentów |
| Worst Fit | Największy blok | Pozostawia użyteczne resztki | Niszczy duże bloki |
| Next Fit | First Fit od ostatniego miejsca | Rozproszenie | Fragmentacja |
3. Stronicowanie (Paging)
Idea
Dzielimy pamięć na równe bloki (strony/ramki):
- Strona (Page) - blok pamięci wirtualnej (4KB typowo)
- Ramka (Frame) - blok pamięci fizycznej (ten sam rozmiar)
┌─────────────────────────────────────────────────────────────────┐
│ PAMIĘĆ WIRTUALNA PAMIĘĆ FIZYCZNA │
│ (przestrzeń adresowa) (RAM) │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Strona 0│─────────────────────────│ Ramka 5 │ │
│ ├─────────┤ ├─────────┤ │
│ │ Strona 1│──────────┐ │ Ramka 1 │ │
│ ├─────────┤ │ ├─────────┤ │
│ │ Strona 2│────┐ │ │ Ramka 2 │←──────────┐ │
│ ├─────────┤ │ │ ├─────────┤ │ │
│ │ Strona 3│ │ └─────────────→│ Ramka 3 │ │ │
│ └─────────┘ │ ├─────────┤ │ │
│ │ │ Ramka 4 │ │ │
│ │ ├─────────┤ │ │
│ └───────────────────→│ Ramka 7 │ │ │
│ └─────────┘ │ │
│ │ │
│ TABLICA STRON (Page Table) Strona 2 → Ramka 7────┘ │
│ ┌──────────────────────┐ │
│ │ Strona │ Ramka │Flagi│ │
│ │ 0 │ 5 │ RW │ │
│ │ 1 │ 3 │ R │ │
│ │ 2 │ 7 │ RW │ │
│ │ 3 │ - │ INV │ ← Strona nie w pamięci (page fault) │
│ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Translacja adresu
Adres wirtualny (32-bit, strony 4KB):
┌────────────────────────┬──────────────┐
│ Numer strony (20b) │ Offset (12b) │
└────────────────────────┴──────────────┘
│ │
↓ │
Tablica stron │
│ │
↓ │
┌────────────────────────┬──────────────┐
│ Numer ramki (20b) │ Offset (12b) │
└────────────────────────┴──────────────┘
Adres fizyczny
Wielopoziomowe tablice stron
Problem: Tablica stron dla 32-bit przestrzeni z 4KB stronami = 2²⁰ wpisów × 4B = 4MB per proces!
Rozwiązanie: Hierarchiczna tablica stron
Adres wirtualny (32-bit, 2 poziomy):
┌────────────┬────────────┬──────────────┐
│ Katalog(10)│ Tabela(10) │ Offset (12) │
└────────────┴────────────┴──────────────┘
│ │ │
↓ ↓ │
┌──────────┐ ┌──────────┐ │
│ Page │ │ Page │ │
│Directory │→ │ Table │→ Ramka + Offset
└──────────┘ └──────────┘
64-bit (x86-64): 4 poziomy (PML4 → PDPT → PD → PT)
TLB (Translation Lookaside Buffer)
Problem: Każdy dostęp do pamięci wymaga 2+ odczytów (tablica + dane).
Rozwiązanie: Cache translacji adresów
┌─────────────────────────────────────────────────────────────────┐
│ TLB │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Strona wirtualna │ Ramka fizyczna │ Flagi │ ASID │ │
│ │ 0x12345 │ 0x789AB │ RW │ 42 │ │
│ │ 0x12346 │ 0x789AC │ R │ 42 │ │
│ │ ... │ ... │ ... │ ... │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ TLB hit: ~1 cykl │
│ TLB miss: ~100+ cykli (page walk) │
│ Hit rate: >99% typowo │
└─────────────────────────────────────────────────────────────────┘
Zalety i wady stronicowania
| Zalety | Wady |
|---|---|
| Brak fragmentacji zewnętrznej | Fragmentacja wewnętrzna (ostatnia strona) |
| Prosta alokacja (bitmapa ramek) | Narzut tablicy stron |
| Łatwe współdzielenie (COW) | TLB miss kosztowny |
| Pamięć wirtualna naturalna | Nie odpowiada strukturze programu |
4. Segmentacja (Segmentation)
Idea
Dzielimy pamięć na logiczne segmenty odpowiadające strukturze programu:
- Segment kodu
- Segment danych
- Segment stosu
- Segment bibliotek
┌─────────────────────────────────────────────────────────────────┐
│ PRZESTRZEŃ LOGICZNA PAMIĘĆ FIZYCZNA │
│ │
│ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ Segment 0 │ │ │ │
│ │ (Kod) │─────────────────│→ 0x1000 - 0x3FFF │ │
│ │ Rozmiar: 12KB │ │ │ │
│ └─────────────────┘ ├─────────────────────┤ │
│ ┌─────────────────┐ │ │ │
│ │ Segment 1 │─────────────────│→ 0x8000 - 0xBFFF │ │
│ │ (Dane) │ │ │ │
│ │ Rozmiar: 16KB │ ├─────────────────────┤ │
│ └─────────────────┘ │ │ │
│ ┌─────────────────┐ │ │ │
│ │ Segment 2 │─────────────────│→ 0xF000 - 0xF7FF │ │
│ │ (Stos) │ │ │ │
│ │ Rozmiar: 2KB │ └─────────────────────┘ │
│ └─────────────────┘ │
│ │
│ TABLICA SEGMENTÓW │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Segment │ Baza │ Limit │ Prawa │ │ │
│ │ 0 │ 0x1000 │ 12KB │ RX │ (kod - execute) │ │
│ │ 1 │ 0x8000 │ 16KB │ RW │ (dane - read/write) │ │
│ │ 2 │ 0xF000 │ 2KB │ RW │ (stos) │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Translacja adresu
Adres logiczny:
┌────────────────────┬──────────────────────┐
│ Numer segmentu (s) │ Offset (d) │
└────────────────────┴──────────────────────┘
│ │
↓ │
Tablica segmentów │
┌──────┬───────┐ │
│ Baza │ Limit │ │
└──────┴───────┘ │
│ │ │
│ Sprawdź: d < Limit?
│ │ │
↓ ↓ │
Adres fizyczny = Baza + Offset
Ochrona w segmentacji
Każdy segment ma prawa dostępu:
- R (Read) - odczyt dozwolony
- W (Write) - zapis dozwolony
- X (Execute) - wykonanie dozwolone
Segment kodu: RX (wykonaj, nie modyfikuj)
Segment danych: RW (czytaj/pisz, nie wykonuj)
Segment stosu: RW (bez wykonywania - ochrona przed exploitami)
Zalety i wady segmentacji
| Zalety | Wady |
|---|---|
| Odpowiada strukturze programu | Fragmentacja zewnętrzna |
| Naturalna ochrona (per segment) | Segmenty o zmiennej wielkości |
| Łatwe współdzielenie (cały segment) | Kompaktowanie potrzebne |
| Dynamiczny wzrost segmentów | Skomplikowana alokacja |
5. Porównanie: Stronicowanie vs Segmentacja
| Cecha | Stronicowanie | Segmentacja |
|---|---|---|
| Jednostka | Strona (stały rozmiar) | Segment (zmienny rozmiar) |
| Widoczność dla programisty | Niewidoczna | Widoczna (logiczne jednostki) |
| Fragmentacja zewnętrzna | ❌ Brak | ✅ Występuje |
| Fragmentacja wewnętrzna | ✅ Występuje | ❌ Brak |
| Tablica | Tablica stron (duża) | Tablica segmentów (mała) |
| Ochrona | Per strona (mniej naturalna) | Per segment (naturalna) |
| Współdzielenie | Per strona | Per segment (całe moduły) |
| Pamięć wirtualna | Łatwa (strony na dysk) | Trudniejsza |
6. Segmentacja ze stronicowaniem (Hybrid)
Intel x86 (tryb chroniony)
Kombinacja obu mechanizmów:
Adres logiczny (Selector:Offset)
│
↓
SEGMENTACJA
(Segment → Adres liniowy)
│
↓
Adres liniowy
│
↓
STRONICOWANIE
(Strona → Ramka)
│
↓
Adres fizyczny
Praktyka: Współczesne OS (Linux, Windows) używają flat memory model - wszystkie segmenty pokrywają całą przestrzeń adresową, efektywnie wyłączając segmentację.
Zalety hybrydowego podejścia
- Ochrona z segmentacji (kod vs dane vs stos)
- Brak fragmentacji zewnętrznej ze stronicowania
- Pamięć wirtualna ze stronicowania
7. Pamięć wirtualna (Virtual Memory)
Idea
Nie wszystkie strony muszą być w RAM - część może być na dysku (swap).
┌─────────────────────────────────────────────────────────────────┐
│ │
│ PAMIĘĆ WIRTUALNA RAM DYSK (Swap) │
│ ┌─────────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Strona 0 │ ────→│ Ramka 2 │ │ │ │
│ │ Strona 1 │ │ │ │ Strona 3 │ │
│ │ Strona 2 │ ────→│ Ramka 5 │ │ Strona 5 │ │
│ │ Strona 3 │ ─────────────────────→ │ │ │
│ │ Strona 4 │ ────→│ Ramka 1 │ │ │ │
│ │ Strona 5 │ ─────────────────────→ │ │ │
│ └─────────────┘ └──────────┘ └──────────────┘ │
│ │
│ Page fault: Strona 3 → załaduj z dysku do RAM │
└─────────────────────────────────────────────────────────────────┘
Algorytmy zastępowania stron
| Algorytm | Opis | Właściwości |
|---|---|---|
| FIFO | Najstarsza strona | Prosty, anomalia Bélády'ego |
| LRU | Najdawniej używana | Optymalny offline, kosztowny |
| LRU Approximation | Clock, Second Chance | Praktyczny kompromis |
| LFU | Najrzadziej używana | Dobre dla hot data |
| OPT | Najdalej używana | Teoretycznie optymalny, niemożliwy |
Algorytm Clock (Second Chance)
┌───┐
┌──→│ 1 │──┐ Bit referencji:
│ └───┘ │ 1 = używana ostatnio
│ ↓ 0 = kandydat do usunięcia
┌───┐ ┌───┐
│ 0 │ │ 1 │ Wskazówka zegara:
└───┘ └───┘ - Jeśli bit=1: zeruj, idź dalej
↑ │ - Jeśli bit=0: zastąp tę stronę
│ ┌───┐ │
└───│ 0 │←─┘
└───┘
↑
wskazówka
🧠 Mnemoniki
"STRONY RÓWNE, SEGMENTY LOGICZNE":
- Strony = wszystkie takie same (4KB)
- Segmenty = różne rozmiary, logiczny podział
"PAGE = Physical Allocation Generates Equality":
- Fizyczne ramki równej wielkości
- Brak fragmentacji zewnętrznej
"SEGMENT = Software Entity with Guarded Memory, ENforcing Type safety":
- Logiczne jednostki programu
- Ochrona per segment
"TLB = Translation Lightning-fast Buffer":
- Cache dla translacji adresów
- Hit = 1 cykl, Miss = 100+ cykli
"LRU = Last Recently Used → pierwszy do usunięcia":
- Najdawniej używana = najlepsza do wyrzucenia
❓ Możliwe pytania dodatkowe (follow-up)
Q1: "Co to jest Page Fault i jak jest obsługiwany?"
Odpowiedź:
Page Fault = wyjątek gdy strona nie jest w RAM (bit valid=0 w tablicy stron).
1. Proces odwołuje się do adresu w stronie 5
2. MMU sprawdza tablicę stron: strona 5 invalid
3. Page Fault exception
4. OS:
a) Znajdź stronę na dysku (swap)
b) Znajdź wolną ramkę (lub zwolnij przez algorytm zastępowania)
c) Załaduj stronę z dysku do RAM
d) Zaktualizuj tablicę stron (valid=1, ramka=X)
e) Wznów instrukcję
5. Proces kontynuuje (nie wie, że był page fault)
Q2: "Wyjaśnij anomalię Bélády'ego"
Odpowiedź:
Anomalia Bélády'ego = więcej ramek → więcej page faults (dla FIFO)!
Sekwencja odwołań: 1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5
3 ramki (FIFO): 9 page faults
4 ramki (FIFO): 10 page faults (!!)
Wniosek: FIFO nie jest "stack algorithm" - nie ma tej właściwości:
"Strony w pamięci z N ramkami ⊆ strony z N+1 ramkami"
LRU nie ma tej anomalii (jest stack algorithm).
Q3: "Co to jest thrashing?"
Odpowiedź:
Thrashing = system spędza więcej czasu na page faults niż na wykonywaniu kodu.
Przyczyna: Zbyt mało RAM dla working set procesów
Working set = zbiór stron aktywnie używanych przez proces
Symptomy:
- CPU utilization spada
- Dysk ciągle pracuje (swap in/out)
- System "zamiera"
Rozwiązania:
- Zwiększ RAM
- Zmniejsz multiprogramming
- Working set model (przydziel RAM proporcjonalnie)
- Swap na SSD
Q4: "Jak działa Copy-on-Write?"
Odpowiedź:
COW = odroczenie kopiowania do momentu modyfikacji.
fork() bez COW:
Rodzic: [Strona A] [Strona B] [Strona C]
↓ kopiowanie
Dziecko: [Strona A'] [Strona B'] [Strona C']
→ Kosztowne!
fork() z COW:
Rodzic: [Strona A (RO)] [Strona B (RO)] [Strona C (RO)]
↓ shared ↓ shared ↓ shared
Dziecko: [Strona A (RO)] [Strona B (RO)] [Strona C (RO)]
→ Szybkie! (tylko tablice stron)
Dziecko pisze do Strony B:
1. Page fault (strona RO)
2. OS kopiuje Stronę B → B'
3. Dziecko dostaje B' (RW), rodzic zachowuje B (RW)
Q5: "Jaki jest typowy rozmiar strony i dlaczego?"
Odpowiedź:
| Rozmiar | Zalety | Wady |
|---|---|---|
| Mały (1KB) | Mała fragmentacja wewnętrzna | Duża tablica stron |
| Duży (64KB) | Mała tablica stron | Duża fragmentacja wewnętrzna |
| 4KB (typowy) | Kompromis | Kompromis |
Dlaczego 4KB?
- Rozmiar bloku dysku (sektor 512B × 8 lub 4K native)
- Rozsądna fragmentacja (~2KB średnio)
- Rozsądna tablica stron
- Historyczne (VAX, Unix)
Huge Pages (2MB, 1GB):
- Dla dużych aplikacji (bazy danych)
- Mniej wpisów TLB
- Mniej page faults
Q6: "Jak segmentacja jest używana w x86-64?"
Odpowiedź:
x86-64 praktycznie nie używa segmentacji:
CS, DS, ES, SS → Baza = 0, Limit = maksymalny
→ Efektywnie "flat model"
Wyjątki:
- FS, GS → używane dla Thread Local Storage (TLS)
- CS → poziom uprzywilejowania (ring 0/3)
Powód: Segmentacja komplikuje pamięć wirtualną i nie jest potrzebna z ochroną per-strona (NX bit, SMEP, SMAP).
🎯 Kluczowe punkty do zapamiętania
- Stronicowanie = równe strony/ramki, brak fragmentacji zewnętrznej
- Segmentacja = logiczne jednostki, fragmentacja zewnętrzna
- Współczesne OS = stronicowanie (segmentacja wyłączona)
- TLB = cache translacji, kluczowy dla wydajności
- Page fault = strona nie w RAM, załaduj z dysku
- Thrashing = za mało RAM, ciągłe page faults
📖 Źródła do pogłębienia
- Silberschatz, Galvin - "Operating System Concepts"
- Tanenbaum - "Modern Operating Systems"
- Intel Manual Vol. 3 - System Programming Guide
- Linux kernel documentation - Memory Management