Zarządzanie pamięcią w systemie Linux: Swap, OOM Killer i Cgroups

12 min czytania - 31 maja 2026

hero section cover
Spis treści
  • Wyjaśnienie zarządzania pamięcią w systemie Linux: swap, OOM killer i cgroups
  • Jak system Linux zarządza stronami pamięci
  • Konfiguracja pamięci wymiany
  • OOM killer
  • Grupy C i limity pamięci
  • Konfiguracja pamięci w zależności od roli serwera
Udostępnij

Jak Linux swap, OOM killer i cgroups współpracują ze sobą - z przykładami konfiguracji dla baz danych, serwerów WWW i hostów VPS z wieloma dzierżawcami.

Wyjaśnienie zarządzania pamięcią w systemie Linux: swap, OOM killer i cgroups

System Linux obsługuje pamięć inaczej niż większość systemów operacyjnych. Wysokie zużycie pamięci RAM nie zawsze stanowi problem — jądro aktywnie wykorzystuje wolną pamięć do buforowania w celu przyspieszenia odczytu z dysku. Jednak gdy pojawia się rzeczywisty nacisk na pamięć, zadziałają trzy mechanizmy: swap, OOM killer i cgroups. Zrozumienie działania każdego z nich oraz sposobu ich konfiguracji stanowi różnicę między serwerem, który płynnie radzi sobie z obciążeniem, a serwerem, który ulega awarii bez ostrzeżenia.

Jak system Linux zarządza stronami pamięci

Każdy proces działa we własnej wirtualnej przestrzeni adresowej, która w systemach 64-bitowych może mieć rozmiar do 128 TB. Jądro mapuje te adresy wirtualne na fizyczną pamięć RAM za pomocą tabel stron, a bufor TLB (Translation Lookaside Buffer) buforuje ostatnie wyszukiwania. Trafienie w TLB zajmuje około 1 nanosekundy; brak trafienia kosztuje 20–100 nanosekund, co sumuje się w przypadku obciążeń intensywnie wykorzystujących pamięć, takich jak bazy danych.

Pamięć fizyczna jest podzielona na strony o wielkości 4 KB, a jądro dzieli je na dwie kategorie:

  • Strony oparte na plikach — powiązane z plikami na dysku. Jądro może odrzucać czyste strony lub opróżniać brudne bez konieczności korzystania z pamięci wymiany.
  • Strony anonimowe — pamięć sterty i stosu bez pliku podkładowego. Muszą one zostać zapisane w pamięci wymiany, zanim jądro będzie mogło je zwolnić.

Na serwerach o dużym zapotrzebowaniu na pamięć duża część stron anonimowych oznacza, że pamięć wymiany jest angażowana wcześnie. Obserwuj si (swap in) i so (swap out) w vmstat 1 — stałe wartości niezerowe to pierwszy sygnał ostrzegawczy, że system jest obciążony.

Do monitorowania użyj odpowiedniego narzędzia:

NarzędzieNajlepsze doKluczowy wskaźnik
free -hSzybki przegląd całego systemuavailable kolumna
vmstat 1Monitorowanie wymiany pamięci i operacji wejścia/wyjścia w czasie rzeczywistymsi, so
htopInteraktywny widok poszczególnych procesówPaski pamięci, lista procesów
smemDokładne wykorzystanie pamięci na procesUSS (rozmiar unikalnego zestawu)
/proc/meminfoSzczegóły na poziomie jądraMemAvailable, Dirty, Slab

Jeden z częstych błędów: obserwowanie free kolumny free -h i panikowanie. Liczy się kolumna available kolumna ma znaczenie. Obejmuje ona pamięć, którą jądro może odzyskać z pamięci podręcznej na żądanie. Serwer pokazujący tylko 512 MB wolnej pamięci, ale 5 GB dostępnej, nie ma problemów.

Gdy ilość pamięci spadnie poniżej progu, kswapd w tle. Jeśli to nie wystarczy, jądro przechodzi do trybu bezpośredniego odzyskiwania, blokując procesy do momentu zwolnienia stron. Stąd biorą się skoki opóźnień. Ustaw alert, gdy MemAvailable spadnie poniżej 10–15% całkowitej pamięci RAM, abyś miał czas na reakcję


 

Konfiguracja pamięci wymiany

Pamięć wymiany to obszar dysku — partycja lub plik — do którego jądro przenosi nieaktywne strony anonimowe, gdy pamięć RAM się zapełni. Różnica w szybkości jest znaczna: pamięć RAM DDR4 ma opóźnienie około 100 ns, podczas gdy dyski SSD NVMe mają opóźnienie około 100 000 ns, a dyski SSD SATA – blisko 500 000 ns. Pamięć wymiany jest buforem bezpieczeństwa, a nie dodatkową pamięcią RAM. Serwer, który stale polega na pamięci wymiany, ma problem z pamięcią, którego nie rozwiąże zwiększenie jej rozmiaru.

Używaj pliku swap zamiast partycji. Łatwiej jest zmienić jego rozmiar i nie wymaga to ponownego partycjonowania.

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

Dodaj plik do /etc/fstab , aby zachować go po ponownym uruchomieniu. chmod 600 krok jest wymagany — wszelkie dane wyładowane z pamięci RAM są czytelne z pliku swap, więc plik nie może być ogólnodostępny do odczytu.

Po utworzeniu pliku swap dostosuj vm.swappiness. Domyślna wartość 60 jest agresywna. W przypadku większości obciążeń hostingowych chcesz, aby jądro preferowało pamięć RAM i używało pliku wymiany tylko w ostateczności:

Rola serweravm.swappinessvm.vfs_cache_pressure
Ogólny serwer WWW10–2050
Baza danych (MySQL/PostgreSQL)1–550
Domyślnie (większość dystrybucji)60100

Jeśli chodzi o rozmiar partycji swap: 1–2 GB wystarczy dla VPS o pojemności 2 GB, obsługującego sporadyczne skoki ruchu. W systemach z 8 GB lub więcej pamięci RAM zazwyczaj wystarcza stała partycja swap o rozmiarze 2–4 GB. Celem jest zapewnienie jądru zaworu bezpieczeństwa dla stron zimnych, a nie rozszerzenie całkowitej pamięci adresowalnej.

Na serwerach z ograniczoną pamięcią RAM, ale z wystarczającą mocą procesora, zram tworzy skompresowany obszar wymiany w pamięci, całkowicie unikając operacji wejścia/wyjścia na dysku. Warto to rozważyć w przypadku hostów VPS z wieloma najemcami, gdzie NVMe jest współdzielone między najemcami. Należy uważać na konflikty wejścia/wyjścia, jeśli obszar wymiany znajduje się na tym samym urządzeniu co pliki bazy danych — intensywna wymiana i zapis na dysku o dużej przepustowości nie współistnieją dobrze.

OOM killer

Gdy jądro wyczerpie pamięć RAM i pamięć wymiany i nie może odzyskać wystarczającej ilości pamięci innymi sposobami, wkracza OOM killer. Ocenia on procesy za pomocą funkcji oom_badness() funkcji:

points = (rss_anon + rss_file + rss_shmem + swapents + pgtables_pages) + (oom_score_adj × totalpages / 1000)

Proces z najwyższą oceną zostaje zabity. Formuła faworyzuje procesy zużywające dużo pamięci, a jądro unika zabijania wielu procesów w krótkich odstępach czasu, sprawdzając, czy dany proces nie został już zakończony w ciągu ostatnich 5 sekund.

W logach pojawiają się dwa rodzaje zdarzeń OOM:

  • Globalny OOM — w całym systemie zabrakło pamięci RAM i przestrzeni wymiany. Logi mają prefiks Out of memory:
  • Cgroup OOM — kontener lub usługa osiągnęły swój memory.max limit. Logi mają prefiks Memory cgroup out of memory:

Aby przejrzeć poprzednie zdarzenia OOM:

dmesg -T | grep -i "out of memory"
journalctl -k --grep="oom"

Zwróć uwagę na order w logach OOM. Wartość powyżej 0 sugeruje raczej fragmentację pamięci niż jej całkowite wyczerpanie — jądro nie mogło znaleźć wystarczającej liczby ciągłych stron, nawet przy dostępnej wolnej pamięci.

Możesz wpłynąć na to, które procesy są celem OOM killera, dostosowując /proc/<pid>/oom_score_adj. Zakres wynosi od -1000 (nigdy nie zabijaj) do +1000 (zabijaj jako pierwszy). W przypadku usług zarządzanych przez systemd ustaw to na stałe w pliku jednostki:

[Service]
OOMScoreAdjust=-1000

Dodatkowe parametry sysctl do dostosowywania zachowania OOM:

ParametrWartośćEfekt
vm.overcommit_memory0Domyślny tryb heurystycznego nadmiernego przydzielania
vm.overcommit_memory2Tryb ścisły; zapobiega alokacjom przekraczającym RAM × overcommit_ratio + swap
vm.panic_on_oom1Restartuje zamiast zabijać proces
vm.oom_kill_allocating_task1Zabija proces, który wywołał OOM, zamiast największego konsumenta

W celu proaktywnego monitorowania sprawdź /proc/pressure/memory (Pressure Stall Information, dostępne od jądra 4.20). Obserwuj some avg10 wartość: poniżej 5% oznacza prawidłowy stan, utrzymywanie się powyżej 20% oznacza, że prawdopodobnie zbliża się zdarzenie OOM. Rosnący allocstall licznika w /proc/vmstat jest kolejnym wczesnym sygnałem — zlicza on bezpośrednie zatrzymania związane z odzyskiwaniem pamięci, które często poprzedzają zabijanie procesów z powodu OOM. Narzędzia takie jak systemd-oomd lub earlyoom mogą reagować na progi PSI, zanim uruchomi się mechanizm OOM killer jądra

Grupy C i limity pamięci

Grupy kontrolne (cgroups) pozwalają organizować procesy w grupy i egzekwować sztywne limity zasobów. Wprowadzone w systemie Linux 2.6.24, stanowią podstawę środowisk uruchomieniowych kontenerów, w tym Docker, Podman, Kubernetes i LXC. Jądro śledzi wykorzystanie pamięci dla każdej grupy cgroup, obejmując pamięć anonimową, strony oparte na plikach oraz obiekty jądra. Jeśli grupa cgroup osiągnie swój limit, jądro odzyskuje pamięć w ramach tej grupy lub uruchamia zabicie procesu w zakresie grupy cgroup z powodu braku pamięci (OOM).

Cgroup v1 i v2 różnią się przede wszystkim strukturą. W wersji v1 każdy kontroler (pamięć, procesor, wejście/wyjście) jest montowany oddzielnie pod /sys/fs/cgroup/<controller>/, co prowadzi do niespójnego śledzenia zasobów. Wersja v2 wykorzystuje ujednoliconą hierarchię w /sys/fs/cgroup/. Kubernetes przeszedł na wersję v2 jako domyślną w wersji 1.25 i zrezygnował ze wsparcia dla v1 w wersji 1.31.

Aby sprawdzić, której wersji używa Twój system:

stat -fc %T /sys/fs/cgroup/

cgroup2fs oznacza v2; tmpfs zazwyczaj oznacza wersję v1.

FunkcjaCgroup v1Cgroup v2
HierarchiaWiele, na kontrolerPojedyncza, ujednolicona
Sztywny limit pamięcimemory.limit_in_bytesmemory.max
Miękki limit pamięcimemory.soft_limit_in_bytesmemory.high (ograniczenia przepustowości)
Śledzenie wykorzystaniamemory.usage_in_bytesmemory.current
Wskaźniki ciśnieniaOgraniczonePSI zintegrowane

Kluczowe elementy sterujące pamięcią w cgroup v2:

ParametrTypOpis
memory.maxTwardy limitPrzekroczenie tej wartości uruchamia mechanizm OOM killer
memory.highOgraniczenie miękkieOgranicza alokację i uruchamia odzyskiwanie pamięci przed osiągnięciem limitu twardego
memory.lowOchrona miękkaPamięć poniżej tego progu jest odzyskiwana jako ostatnia
memory.minOchrona twardaPamięć poniżej tego poziomu nigdy nie jest odzyskiwana
memory.swap.maxLimit wymianyUstaw na 0, aby wyłączyć wymianę dla tej grupy cgroup
memory.oom.groupBooleanJeśli opcja jest włączona, OOM zabija wszystkie procesy w cgroup jednocześnie

Praktyczna zasada: ustaw memory.high około 10–20% poniżej memory.max , aby dać jądru miejsce na odzyskanie pamięci przed osiągnięciem twardego limitu. Przy określaniu rozmiaru memory.max, dodaj 20–30% powyżej szczytowego zużycia aplikacji, aby uwzględnić pamięć podręczną stron, która wlicza się do sumy pamięci cgroup.

Zarządzaj grupami cgroup za pośrednictwem systemd zamiast zapisywać bezpośrednio w systemie plików cgroup. Używaj dyrektyw plików jednostek, takich jak MemoryMax=, MemoryHigh=i MemoryMin= dla limitów trwałych. W przypadku szybkich testów:

systemd-run --scope -p MemoryMax=512M <command>

W przypadku pul procesów roboczych serwera WWW ustawienie memory.oom.group=1 zapewnia czyste zakończenie działania, jeśli jeden proces roboczy przekroczy swój limit — nie pozostawiając żadnych osieroconych procesów. W przypadku silników baz danych memory.min chroni pulę buforów przed odzyskaniem w sytuacji obciążenia całego systemu.

Konfiguracja pamięci w zależności od roli serwera

Właściwe ustawienia pamięci zależą od tego, do czego służy serwer. Zastosowanie tej samej konfiguracji do bazy danych i serwera WWW PHP spowoduje uszkodzenie jednego z nich.

Rola serweravm.swappinessStrategia OOMPolityka Cgroup
Baza danych1–5Ochrona (OOMScoreAdjust=-900)Użyj memory.min w celu ochrony puli buforów
Serwer WWW/aplikacji10–20DomyślnieLimit na pulę pracowników poprzez memory.max
Pracownik w tle60Możliwość zabicia (OOMScoreAdjust=+200)Ograniczanie przepustowości za pomocą memory.high
Wielodostępny serwer VPS60 (z zram)DomyślnieTwarda izolacja na dzierżawcę poprzez memory.max

W przypadku MySQL i PostgreSQL przydziel 50–70% dostępnej pamięci RAM innodb_buffer_pool_size, wyłącz Transparent Huge Pages, aby zmniejszyć skoki opóźnień, i zabezpiecz proces za pomocą OOMScoreAdjust=-900 w pliku jednostki systemd.

W przypadku PHP-FPM należy dostosować wielkość pul pracowników do rzeczywistego zużycia pamięci. Każdy pracownik zużywa zazwyczaj 30–100 MB. Należy podzielić przydzieloną pamięć RAM przez średnią wielkość pracownika, aby uzyskać bezpieczną pm.max_children wartość. Użyj memory.max w cgroups, aby ograniczyć pulę.

W przypadku obciążeń wymagających intensywnego zapisu ustaw vm.dirty_ratio na około 10%, a vm.dirty_background_ratio na 3%. Spowoduje to częstsze opróżnianie brudnych stron, co pozwoli uniknąć długich przestojów operacji wejścia/wyjścia

Zapewnij trwałość dostrojenia jądra, zapisując parametry w /etc/sysctl.d/90-memory.conf. Ustawienia zastosowane w czasie działania systemu zostaną utracone po ponownym uruchomieniu.

Podsumowanie zalecanych wartości według roli:

ParametrSerwer WWW/aplikacjiSerwer bazy danych
vm.swappiness10–201–5
vm.vfs_cache_pressure5050
vm.dirty_ratio1510%
vm.min_free_kbytes6553665536
Ochrona przed wyczerpaniem pamięciDomyślnieOOMScoreAdjust=-1000

Jeśli obsługujesz obciążenia o dużej gęstości i potrzebujesz serwera z wystarczającą rezerwą mocy, aby prawidłowo stosować te zasady, warto przyjrzeć się serwerom dedykowanym FDC.

Blog

Polecane w tym tygodniu

Więcej artykułów
Zarządzanie pamięcią w systemie Linux: Swap, OOM Killer i Cgroups

Zarządzanie pamięcią w systemie Linux: Swap, OOM Killer i Cgroups

Jak Linux swap, OOM killer i cgroups współpracują ze sobą - z przykładami konfiguracji dla baz danych, serwerów WWW i hostów VPS z wieloma dzierżawcami.

12 min czytania - 31 maja 2026

Przewodnik konfiguracji Prometheus i node_exporter

15 min czytania - 29 maja 2026

Więcej artykułów
background image

Masz pytania lub potrzebujesz niestandardowego rozwiązania?

icon

Elastyczne opcje

icon

Globalny zasięg

icon

Natychmiastowe wdrożenie

icon

Elastyczne opcje

icon

Globalny zasięg

icon

Natychmiastowe wdrożenie