Pamięć współdzielona - Wydział Fizyki i Informatyki Stosowanej

Transkrypt

Pamięć współdzielona - Wydział Fizyki i Informatyki Stosowanej
Model pamięci w systemie Linux
Patryk Konopka
Paweł Piecyk
Wydział Fizyki i Informatyki Stosowanej
2013.05.08
Plan prezentacji
1.
Tryb rzeczywisty i segmentowy model pamięci
2.
Tryb chroniony i płaski model pamięci
3.
Pamięć wirtualna
4.
•
Stronicowanie
•
Physical Address Extension
•
Swapowanie
•
Mapowanie pamięci logicznej na fizyczną
•
Problemy dynamicznej alokacji pamięci
•
Pamięć współdzielona
Przydatne narzędzia
Trochę historii – tryb rzeczywisty (real mode)
•
Tryb, który nie zapewnia ochrony pamięci ani
wielozadaniowości
•
Procesor pracuje tak jak Intel 8086
•
20-bitowa szyna danych → można zaadresować max.
1MiB pamięci
•
Wszystkie procesory od 286 do obecnie stosowanych
konstrukcji startują w real mode w celu zapewnienia
kompatybilności
•
Charakterystyczny dla MS-DOS
„640K ought to be
enough for anybody”
Trochę historii – segmentowy model pamięci
•
Program ma wydzielone w pamięci 3 segmenty:
kodu, danych i stos (+ opcjonalne dodatkowe
segmenty danych)
•
Adres – dwie 16-bitowe liczby: numer segmentu
(segment) + przemieszczenie względem początku
segmentu (offset)
•
Format adresu segment:offset
•
Segmenty mogą na siebie nachodzić – przez to wiele
adresów logicznych może wskazywać na jeden
adres fizyczny (dokładnie 4096)
•
Wszystkie procesory od 286 do obecnie
stosowanych konstrukcji
startują w real mode w celu zapewnienia
kompatybilności
PhysicalAddress = Segment * 16 + Offset
Protected mode
•
Tryb pracy mikroprocesorów x86
wprowadzony w mikroprocesorze Intel
80286.
•
Umożliwienie adresowania pamięci
przekraczającej 1MB.
•
Wprowadzenie wielozadaniowości
•
Podstawowy tryb pracy dla systemów
Linux, Windows i BSD
Protected mode
W rejestrze segmentowym przechowujemy „selektor segmentu”:
Do dyspozycji mamy dwie tablice:
-GDT – Global Descriptor Table
Jedna w systemie – zawiera informacje
o kodzie OS i jego danych, dostępna dla
wszystkich procesów
-LDT – Local Descriptor Table
Osobna dla każdego zadania
- 8192 deskryptorów globalnych
- 8192 deskryptorów lokalnych
Physical or
Protected mode – deskryptor segmentu
• Limit segmentu – wielkość segmentu, połączenie obu pól (20 bitowa liczba)
• Adres bazowy oraz Baza – offset segmentu, połączenie trzech pól (32 bitowa liczba)
• Typ – prawa dostępu do segmentu (Write / Read / Execute)
• DPL – poziom uprzywilejowania segmentu
• S – typ deskryptora, jeżeli 0 to opisuje segment systemowy, w przeciwnym wypadku segment danych lub
kodu
• G – ziarnistość (0 – ziarnistość 1B, 1 – ziarnistość 4kB)
• P – informuje czy segment jest załadowany do pamięci
Protected mode
Protected mode
•
To system musi zarządzać trybem chronionym.
•
Programy nie mają dostępu do danych lub kodu z wyższym
priorytetem.
•
Stosowane w obecnych systemach operacyjnych.
Pamięć wirtualna
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.
Implementacja w systemie Linux:
segmentacja + stronicowanie
Stronicowanie
•
Przestrzeń adresowa segmentu jest
podzielona na równe części – strony
•
Rozmiar strony – 4kB dla procesora Intel
•
Pamięć fizyczna podzielona jest na części o
tej samej wielkości co strony nazywane
ramkami
•
Adres logiczny jest tłumaczony na adres
fizyczny z wykorzystaniem tablic stron
Stronicowanie – wielopoziomowe tablice stron
•
Jeśli używalibyśmy prostych
jednopoziomowych tablic stron to musiałyby
one zawierać 2^20 wpisów (4 bajty na wpis =
4 MB pamięci RAM dla każdego procesu)
•
Dwupoziomowe tablice stron redukują tą ilość
przez tworzenie tablic stron tylko dla tych
obszarów pamięci wirtualnej, które są
aktualnie używane
•
Każdy aktywny proces ma przypisany Page
Directory
•
Adres fizyczny PD aktualnie używanego
procesu jest przechowywany w rejestrze cr3
Stronicowanie – wielopoziomowe tablice stron
PAE – Physical Address Extension
•
Rozszerzenie umożliwiające procesorom x86 (32-bit) dostęp do fizycznej przestrzeni
adresowej (RAM) o rozmiarze większym niż 4 GB.
•
Rejestr cr3 wskazuje na PDPT, który zawiera wskaźniki do 4 PD
•
Rozszerzenie to nie powiększa liniowej przestrzeni adresowej procesu, więc
operowanie na pamięci > 4GB jest możliwe tylko z poziomu kernela
PAE Disabled
PAE Enabled
Linux paging model
32bit – używane 2 poziomy. Nie używamy PUD i PMD
32bit z PAE – używane są 3 poziomy. Nie używamy PUD
64bit – używane 3 lub 4 poziomy w zależności od architektury procesora
Swapping
•
Realizowane przez kswapd – kernel swap daemon (kernel thread)
•
kswapd jest inicjalizowany przy uruchamianiu systemu i jest uruchamiany
okresowo zgodnie z licznikiem zwanym kernel swap timer
•
Przy każdym uruchomieniu kswapd sprawdza czy ilość wolnej pamięci nie
jest zbyt niska, jeśli tak to stara się ją zwolnić
•
Do wyznaczenia stron, które mogą być zapisane na dysk używany jest
algorytm postarzania
• Każda strona ma licznik określający jej wiek
• Licznik przy alokacji ustawiany jest domyślnie na 3
• Przy każdym użyciu strony licznik+=3 (maksymalnie 20)
• Co pewien czas licznik-- dla każdej ze stron
• Gdy licznik = 0 dana strona jest dobrym kandydatem do zapisania na dysk
Swapping
•
Podczas projektowania aplikacji działającej w obrębie systemu czasu rzeczywistego
chcemy zminimalizować czas dostępu do pamięci.
•
Nie chcemy, aby nasza pamięć była swap’owana, swap = długi czas odczytu pamięci.
•
Jak się uchronić przed swap’owaniem?
mlock() lub mlockall() – gwarancja na to, że nasza pamięć pozostanie
w pamięci fizycznej (nie będzie swap’owana)
#include <sys/mman.h>
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
int mlockall(int flags);
int munlockall(void);
MMU – Memory Management Unit
User space
Kernel space
MMU – Memory Management Unit
•
Układ realizujący dostęp do pamięci
fizycznej żądanej przez CPU
•
Realizacja translacji pamięci wirtualnej do
pamięci fizycznej (hardware’owo)
•
Ochrona pamięci
•
Pamięć podręczna
•
Dzielenie pamięci wirtualnej na strony o
rozmiarze 2N
Motorola 68451 – MMU dla procesora
Motorola 68010 w postaci osobnego układu
MMU – Memory Management Unit
•
TLB – Translation Lookaside Buffer
•
Tablica buforująca strony
•
Szybki dostęp do stron
MMU:
•Odpowiedzialny za
Segmentation fault !
•Sygnał SIGSEGV
Segmentation fault
- Dereferencja wskaźników wskazujących na NULL
- Próba dostępu do pamięci do której nie mamy uprawnień
- Próba dostępu do nieistniejącego adresu w pamięci
- Próba zapisu do pamięci typu read-only
- Przepełnienie bufora
- Użycie niezainicjalizowanego wskaźnika
- Próba odpalenia źle skompilowanego programu
Text segment
Text segment
•
Zawiera kod maszynowy przeznaczony do wykonania przez procesor
komputera.
•
Segment kodu jest wskazywany przez rejestr segmentowy CS.
•
Pamięć oznaczona przez system jako read-only – dane nie mogą być
modyfikowane przez proces.
•
Procesy mogą współdzielić kod, w momencie gdy uruchomiona jest kopia
programu.
•
Można wyłączyć współdzielenie kodu w momencie kompilacji za pomocą
flagi –N.
Data segment
Data segment
Miejsce, w którym przechowywane są :
-zmienne globalne z przypisaną wartością
int i = 1;
int main()
{}
- zmienne statyczne z przypisaną wartością
int main()
{
static char *text = „Hello”;
}
BSS segment
BSS segment
Wykorzystywane przez kompilatory i linkery w celu przechowywania
•
zaalokowanych, ale niezainicjowanych zmiennych statycznych.
void dummy()
{
static int i;
}
•
Przechowywanie niezainicjowanych zmiennych globalnych.
int i;
int main()
{}
•
Język C:
int i; == int i = 0;
Rozmiar początkowy BSS segment – 4 lub 8 bajtów.
Funkcje sbrk() oraz brk()
Funkcje sbrk() oraz brk()
•
Podstawowe funkcje do zarządzania pamięcią w systemach Unix
•
Kontrolowanie rozmiaru dostępnej pamięci konkretnego procesu
w sekcji Heap
•
Funkcje wysokopoziomowe
•
Funkcje wykorzystywane przez malloc()
•
Kiedyś w systemach Unix’owych: jedyny sposób na zażądanie
dostępu do dodatkowej pamięci.
Funkcje sbrk() oraz brk()
Program brake – wskazuje na pierwszy adres, który jest niedostępny
dla procesu (w kontekście sterty).
#include <unistd.h>
int brk(void *end_data_segment) - ustawia Program brake na adres,
który wskazuje end_data_segment i zmienia rozmiar dostępnej pamięci.
void *sbrk(intptr_t increment) – przesuwa Program brake o ilość
bajtów przekazaną w parametrze increment.
void * ptr = sbrk(0); – zwróci bieżący adres, na który wskazuje
Program break.
Wywołanie systemowe mmap()
Wywołanie systemowe mmap()
mmap() – wywołanie systemowe, które nakazuje systemowi
operacyjnemu odwzorowanie danej części wybranego pliku w
przestrzeni adresowej procesu.
•
Do obszaru pliku odnosimy się jak do zwykłej tablicy bajtów w
pamięci.
•
Eliminacja wywołań systemowych typu read/write.
•
Przyspieszenie działania na dużych plikach.
Wywołanie systemowe mmap()
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t
offset);
•
start - określa adres, w którym chcemy widzieć odwzorowanie pliku. Nie jest
wymagane – zazwyczaj „0”.
•
length - ilość bajtów jaką chcemy odwzorować w pamięci.
•
prot - flagi określające uprawnienia jakie chcemy nadać obszarowi pamięci.
PROT_READ | PROT_WRITE | PROT_EXEC | PROT_NONE
•
flags - dodatkowe flagi określające sposób działania wywołania mmap.
MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS
•
fd - deskryptor pliku, który chcemy odwzorować w pamięci.
•
offset - liczba określająca od którego miejsca w pliku chcemy rozpocząć
Wywołanie systemowe mmap()
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t
offset);
Wartość zwracana:
•
Sukces – zwrócenie wskaźnika na odwzorowaną pamięć.
•
Porażka – zwrócenie MAP_FAILED == (void*)-1.
Wywołanie systemowe munmap()
munmap() - Wywołanie systemowe nakazujące zlikwidowanie odwzorowania
pliku w pamięci.
int munmap(void *start, size_t length);
•start - określa adres odwzorowania do skasowania.
•length - liczba bajtów zajmowana przez odwzorowanie.
Wartość zwracana:
•Sukces – zwrócenie 0.
•Porażka – zwrócenie -1.
Problem dynamicznej alokacji pamięci
•
Funkcja malloc() alokuje pamięć z wykorzystaniem dwóch funkcji:
-
sbrk()
-
mmap()
•
Alokacja pamięci za pomocą sbrk(), gdy n < MMAP_THRESHOLD
•
Alokacja pamięci za pomocą mmap(), gdy n >= MMAP_THRESHOLD,
gdzie n – rozmiar w bajtach
•
Możliwość zmiany MMAP_THRESHOLD za pomocą funkcji mallopt().
int result = mallopt(M_MMAP_THRESHOLD, 128*1024); - wartość domyślna
Problem dynamicznej alokacji pamięci
•
Pojedynczy blok pamięci to tzw. chunk
•
Puste (zwolnione) bloki pamięci tworzą listę
•
Ważne: wywołanie malloc(96) wcale nie zaalokuje bloku
pamięci o rozmiarze 96 bajtów !!!
Wywołanie malloc()
Chunk size
Pointer to next
free chunk
Data
Rys 1. Pojedynczy chunk
Rys 2. Przykład wywołania malloc(96);
Wywołanie free()
Rys 3. Przykład wywołania free(ptr);
Negatywne skutki dynamicznej alokacji fragmentacja
Problem pośredni:
•długi czas przejścia listy
w celu znalezienia
odpowiedniego chunk’a
Fragmentacja – rozwiązanie problemu
Zastosowanie innego algorytmu alokacji np. Best-Fit Allocation
•
Przed:
•
Po:
Czas działania algorytmu O(n), gdzie n – ilość wolnych bloków
Stos
Stos
•
Liniowa struktura danych, w której dane są dokładane na wierzch stosu.
•
Dwie operacje:
- push – umieszczenie wartości na szczycie stosu, czyli przesunięcie
rejestru ESP o odpowiednią ilość bajtów do tyłu i wpisanie tam
wartości
- pop – zdjęcie wartości ze stosu, czyli przesunięcie ESP do przodu
•
Odpowiedzialne rejestry:
SS – rejestr segmentowy, wskazujący na początek stosu
ESP – rejestr wskazujący na element znajdujący się na szczycie stosu
Stos
•
Jak sprawdzić maksymalny rozmiar stosu?
Wywołanie: ulimit -s
Kernel space
Kernel space
Przechowuje:
•Kod kernela
•Dane wykorzystywane przez kernel
•Page tables
Kernel też potrzebuje swojej przestrzeni adresowej !
•Cała pamięć (1GB) jest od razu mapowana na pamięć fizyczną.
•Komunikacja tylko za pomocą wywołań systemowych.
Pamięć współdzielona
Pamięć współdzielona – pamięć do której może mieć jednoczesny dostęp
kilka procesów
Gdzie może się przydać:
- komunikacja między procesami (inter-process communication)
- współdzielenie bibliotek
Pamięć współdzielona – komunikacja między procesami
int segment_id = shmget(segment_id, size, flags) - alokuje pamięć
współdzieloną
void* shmat(segment_id, NULL, flags) - mapuje pamięć współdzieloną
do przestrzeni pamięci procesu
void shmdt(adress) – odłącza pamięć współdzieloną
shmctl() - służy m.in. do zwalniania pamięci współdzielonej
Przydatne narzędzia:
ipcs – pozwala uzyskać informacje dotyczące pamięci
współdzielonej
ipcrm – pozwala usuwać obiekty związane z IPC
Przydatne narzędzia - top
top – narzędzie do monitorowania systemu
W kontekście pamięci najbardziej powinny interesować nas
kolumny:
VIRT – ilość pamięci do której proces ma dostęp w aktualnym momencie,
czyli suma pamięci aktualnie używanej, plików z HDD, która są do niej
zmapowane oraz pamięci współdzielonej.
RES – określa ile pamięci fizycznej jest używane przez proces.
SHR – określa jaka część pamięci z kolumny VIRT jest współdzielona.
Przydatne narzędzia - /proc/pid/status
free – proste narzędzie do statystyki, wyświetla ilość dostępnej/zajętej
pamięci w systemie.
/proc/pid/status – interesujące informacje z przedrostkiem „Vm”
•
VmPeak – maksymalny rozmiar pamięci użyty przez proces w ciągu jego życia,
•
VmSize – rozmiar pamięci wirtualnej,
•
VmLck – ilość zablokowanej pamięci,
•
VmHWM – „High water mark”, maksymalny rozmiar pamięci fizycznej użyty przez
proces,
•
VmRSS – aktualny rozmiar wykorzystywanej pamięci fizycznej,
•
VmData, VmStk, VmExe – poszczególne segmenty,
•
VmPTE – rozmiar tablic stron
•
VmLib – rozmiar kodu bibliotek współdzielonych
Przydatne narzędzia - pmap
pmap -x pid – wyświetla mapę pamięci procesu
Kolumny:
Address – adres początku mapy
Kbytes – rozmiar mapy
RSS – rozmiar zajmowanej pamięci fizycznej
Dirty - dirty pages (both shared and private)
Mode - uprawnienia: read, write, execute, shared, private (kopia przy zapisie)
Mapping – plik z którego pochodzi mapa, lub '[ anon ]' dla zaalokowanej pamięci, lub
'[ stack ]' dla stosu procesu
Przydatne narzędzia – pmap – przykładowy wynik
$ pmap -x 4195
4195:
./process1
Address
Kbytes
0000000000400000
4
0000000000600000
4
0000000000601000
4
00007f770aae7000
1784
00007f770aca5000
2044
00007f770aea4000
16
00007f770aea8000
8
00007f770aeaa000
20
00007f770aeaf000
140
00007f770b0a9000
12
00007f770b0c7000
28
00007f770b0ce000
12
00007f770b0d1000
4
00007f770b0d2000
8
00007fff62113000
132
00007fff621fe000
8
ffffffffff600000
4
---------------- -----total kB
4260
RSS
4
4
4
276
0
16
8
12
116
12
4
12
4
8
12
4
0
-----496
Dirty
0
4
4
0
0
16
8
12
0
12
4
12
4
8
12
0
0
-----96
Mode
r-x-r---rw--r-x-----r---rw--rw--r-x-rw--rw-srw--r---rw--rw--r-x-r-x--
Mapping
process1
process1
process1
libc-2.17.so
libc-2.17.so
libc-2.17.so
libc-2.17.so
[ anon ]
ld-2.17.so
[ anon ]
[ shmid=0x2e0001 ]
[ anon ]
ld-2.17.so
ld-2.17.so
[ stack ]
[ anon ]
[ anon ]
Analiza pamięci - narzędzia
Valgrind – narzędzie do debugowania pamięci, wykrywania wycieków pamięci
oraz profilowania aplikacji. Geneza nazwy: nazwa głównego wejścia do Valhali
w nordyckiej mitologii.
•
Współpraca z gdb:
1. valgrind --vgdb=yes --vgdb-error=0 ./small_app
2. gdb ./small_app
3. (gdb) target remote | vgdb --pid=xxxx
4. (gdb) monitor leak_check full reachable any
Bibliografia
1.
http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory
2.
http://www.advancedlinuxprogramming.com
3.
http://www.cs.rit.edu/~ark/lectures/gc/03_03_03.html Best-Fit Algorithm
4.
http://www.ualberta.ca/CNS/RESEARCH/LinuxClusters/mem.html Understanding Memory
5.
http://technology-shettyprasad.blogspot.com/2010/08/dynamic-memory-management.html
6.
http://en.wikipedia.org
7.
Linux man pages

Podobne dokumenty