8.1 Pamięć operacyjna
Pamięć operacyjna (RAM, RAM) komputera to tablica komórek pamięci, z których każda ma unikalny adres. Te komórki mogą przechowywać dane różnych typów, takie jak liczby, znaki i wskaźniki. Gdy program jest uruchomiony, umieszcza swoje dane i instrukcje w tej pamięci, aby mieć do nich szybki dostęp.
Przykład komórek pamięci:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
Każda komórka ma swój numer porządkowy, zwany także adresem komórki w pamięci lub po prostu adresem. Jeśli twój komputer ma 8 GB pamięci, to ma 8 miliardów takich komórek, w których można przechowywać coś użytecznego.
Bity i bajty
Każda komórka może przechowywać jeden bajt informacji. Każdy bajt składa się z 8 bitów, a każdy bit może zawierać tylko 0 lub 1. Przykład (dla liczb całkowitych dodatnich):
Liczba | Reprezentacja bitowa | Zaokrąglona do bajta |
---|---|---|
0 | 0 | 00000000 |
1 | 1 | 00000001 |
100 | 1100100 | 01100100 |
1000 | 1111101000 | 00000011-11101000 |
1000 000 000 | 111011100110101100101000000000 | 00111011-10011010-11001010-00000000 |
Im więcej bajtów zajmuje zmienna, tym więcej wartości można w niej przechowywać. Przykład:
- 1 bajt — 256 unikalnych wartości
- 2 bajty — 65 tys. unikalnych wartości
- 3 bajty — 16 milionów
- 4 bajty — 4 miliardy
8.2 Jak dane są reprezentowane w pamięci
Typy danych i ich reprezentacja
Dane liczbowe wewnątrz procesora i w pamięci
- Liczby całkowite: przechowywane w postaci binarnej. Rozmiar może się różnić (1 bajt, 2 bajty, 4 bajty).
- Liczby rzeczywiste: przechowywane w formacie zmiennoprzecinkowym (np. format IEEE 754 dla liczb 4-bajtowych i 8-bajtowych).
x = 42 # Liczba całkowita
y = 3.14 # Liczba rzeczywista
Ważne! W Pythonie wbudowane typy int
i float
to pełnoprawne klasy, które mogą realizować skomplikowane obliczenia z liczbami o nieskończonej długości. Jednakże, jeśli będziesz używać bibliotek do obliczeń naukowych lub AI, to napotkasz właśnie ten format danych, o którym mówiłem powyżej.
Dane znakowe w pamięci komputera
Znaki i ciągi są przechowywane w pamięci jako sekwencje bajtów. Na przykład, w kodowaniu ASCII
każdy znak zajmuje 1 bajt, w kodowaniu UTF-8
może zajmować od 1 do 4 bajtów.
W Pythonie 3.x domyślnie dla ciągów stosowane jest kodowanie UTF-8
, ale możesz odczytywać pliki, w których tekst jest przechowywany w innych formatach, lub przesyłać dane przez sieć nie w kodowaniu UTF-8
.
Przykład:
char = 'A' # Znak
string = "Hello, world!" # Ciąg
Pojedyncze znaki w Pythonie nie mają swojego typu - używany jest również typ str
. Jednak w pamięci te ciągi są przechowywane znak po znaku. Jeden znak zwykle zajmuje 1–4 bajty.
Wskaźniki
Wskaźniki przechowują adresy innych komórek pamięci
. Pozwalają one programom na pracę z dynamicznymi strukturami danych i bardziej efektywne zarządzanie pamięcią.
Przykład:
list = [1, 2, 3, 4] # Lista
list_pointer = id(list) # Wskaźnik na początek listy
8.3 Przykłady reprezentacji danych w pamięci operacyjnej
1. Reprezentacja liczb całkowitych
Liczby całkowite są przechowywane w pamięci jako liczby binarne (bity). W zależności od typu danych mogą zajmować różną ilość bajtów. Na przykład, int
zwykle zajmuje 4 bajty (32 bity).
Tak będzie reprezentowana liczba 42 w pamięci:
00000000 | 00000000 | 00000000 | 00101010 |
2. Reprezentacja liczb rzeczywistych (zmiennoprzecinkowych)
Liczby rzeczywiste (na przykład typ float) są przechowywane w pamięci w formacie zmiennoprzecinkowym, zwykle według standardu IEEE 754
. float
zwykle zajmuje 4 bajty (32 bity), a double
— 8 bajtów (64 bity).
Ważne! To są standardowe typy danych związanych z pamięcią i procesorem. Typ float
w Pythonie odpowiada standardowemu typowi double
i zajmuje 8 bajtów.
Tak będzie reprezentowana liczba 3.14 w pamięci:
01000000 | 01001000 | 11110110 | 01100110 |
3. Reprezentacja znaków i ciągów
Znaki (na przykład typ char) są przechowywane w pamięci jako sekwencja bajtów. Ciągi to tablice znaków. W językach C/C++ ciągi kończą się zerowym bajtem (\0), ale w Pythonie tak nie jest.
Tak będzie reprezentowany ciąg Hello
w pamięci:
'H' | 'e' | 'l' | 'l' | 'o' |
Co z kolei będzie reprezentowane w formie 0 i 1:
01001000 | 01100101 | 01101100 | 01101100 | 01101111 |
8.4 Adresowanie dynamicznej pamięci
Dynamiczna pamięć jest przydzielana i zwalniana w trakcie działania programu, w miarę potrzeby. Wszystkie obiekty, które tworzysz w Pythonie, są tworzone w tej pamięci.
Jest podzielona na 2 rodzaje:
Stos (Heap): Obszar pamięci, z którego przydzielane są dynamiczne obiekty. Zarządzanie tą pamięcią odbywa się poprzez funkcje przydziału (np. malloc w C) i zwolnienia (np. free w C).
Stos (Stack): Obszar pamięci używany do przechowywania lokalnych zmiennych i danych wywoływania funkcji. Pamięć jest automatycznie przydzielana i zwalniana przy wejściu i wyjściu z funkcji.
Znów, nie mogę podać przykładu w języku Python, ponieważ jest on zbyt wysokopoziomowy dla takich działań. Mogę znów podać przykład w języku C:
// Dynamiczne przydzielanie pamięci dla tablicy z 10 liczbami całkowitymi
int *dynamic_var = (int *)malloc(sizeof(int) * 10);
// Zwalnianie pamięci
free(dynamic_var);
Adresowanie pamięci to proces określania unikalnego adresu dla każdej komórki pamięci. Każdy adres wskazuje na określoną lokalizację w pamięci, która może zawierać dane lub instrukcje.
Rodzaje adresowania
Adresowanie fizyczne: bezpośredni dostęp do fizycznych adresów komórek pamięci. Zarządza nim sprzęt (np. kontroler pamięci).
Adresowanie wirtualne: używa mechanizmu zarządzania pamięcią, takiego jak pamięć stronicowa lub pamięć segmentowa, aby zapewnić procesom izolowane i chronione przestrzenie adresów.
GO TO FULL VERSION