Server s 1-2 GB RAM potřebuje 1-2 GB swapu, server se 4-8 GB potřebuje 2-4 GB a na databázovém serveru se vyplatí snížit vm.swappiness z 60 na 10. Swap nedostatek paměti neléčí, jen získává čas. Když paměť dojde, OOM killer nezabije proces, který ji snědl, ale ten největší: na našem stendu si PHP požadavek vzal 150 MB navíc a jádro zabilo MariaDB (212 MB), protože samotný PHP worker vážil jen 108 MB.
Tento článek je o VPS nebo vlastním serveru, kde si paměť spravujete sami. Na sdíleném hostingu nastavuje swap a OOM killer poskytovatel, každý účet má vlastní paměťové limity, a místo zabité databáze uvidíte chybu 508 Resource Limit Is Reached nebo hlášení Allowed memory size exhausted.
Jak jsme testovali
10. listopadu 2026 na testovacím stendu: virtuální stroj s jádrem Linux 6.18 a 7,8 GB RAM, bez swapu. Malý VPS jsme napodobili paměťovou cgroup s limitem 320 MB, ve které běžely MariaDB 10.11.14 (buffer pool 128 MB, tabulka 156 MB), PHP-FPM 8.3.6 (4 workery, WordPress 6.4.3) a nginx 1.24. Roli těžkého požadavku hrál PHP skript, který postupně zabere 150 MB. Úvodní stránku jsme načítali každých 0,5 s a události OOM jsme brali z dmesg a z počítadla oom_kill v cgroup. Na sdíleném stroji jsme swap nezapnuli: syntaxi příkazů jsme ověřili, vliv swapu na rychlost jsme neměřili a zram popisujeme podle dokumentace. Dokumentaci jádra, systemd a Red Hat jsme ověřili týž den. Jde o chování testovacího stendu, ne o data ze serverů RichHost.
Proč OOM killer zabije databázi, a ne viníka
Po zahřátí zabírala MariaDB 217 MB rezidentní paměti (RSS), každý worker WordPressu 38 až 46 MB. Pak začal jeden požadavek alokovat paměť po blocích 1 MB, jako to dělá těžký export nebo změna velikosti obrázků. Tohle zapsalo jádro (zkráceno):
[ 6004.066291] php-fpm8.3 invoked oom-killer: gfp_mask=0xcc0(GFP_KERNEL), order=0, oom_score_adj=0 [ 6004.066411] memory: usage 327680kB, limit 327680kB, failcnt 18064 [ pid ] uid tgid total_vm rss rss_anon rss_file rss_shmem pgtables_bytes swapents oom_score_adj name [ 4307] 33 4307 94991 27764 20764 2110 4890 507904 0 0 php-fpm8.3 [ 6440] 0 6440 342132 54366 48160 6206 0 622592 0 0 mariadbd Memory cgroup out of memory: Killed process 6440 (mariadbd) total-vm:1368528kB, anon-rss:192640kB, file-rss:24824kB, shmem-rss:0kB, UID:0 pgtables:608kB oom_score_adj:0
O paměť požádal PHP worker (pid 4307) a zemřela MariaDB. Jádro viníka nehledá. Pro každý proces počítá skóre: rezidentní paměť, stránky ve swapu a tabulky stránek plus korekci oom_score_adj. Zemře proces s nejvyšším skóre. Sloupec rss je ve stránkách po 4 KB: 54 366 stránek databáze je 212 MB, 27 764 stránek workeru je 108 MB. Samotný PHP požadavek pak skončil se stavem 200. Test jsme zopakovali dvakrát a pokaždé zemřela databáze.
Stejný výpis ukazuje, že OOM killer je opravdu poslední krok: předtím jádro narazilo na limit 18 064krát a uvolnilo všechno, co šlo. Souborová cache se zmenšila ze 159 MB na 25 MB a zůstala v ní jen sdílená paměť OPcache.
Co viděli návštěvníci: jeden z 60 požadavků na úvodní stránku dostal chybu 500 “Error establishing a database connection“. Na stendu supervizor mysqld_safe databázi restartoval během téže sekundy. Jednotka systemd pro MariaDB v Ubuntu 24.04 má Restart=on-abnormal a RestartSec=5s, takže na skutečném serveru trvá výpadek nejméně pět sekund. Potom databáze běží se studenou cache: po restartu zabírala 134 MB místo 217 MB a první dotazy šly na disk. Pokud v okamžiku zabití probíhal zápis, InnoDB navíc provádí obnovu po havárii (crash recovery).
Jak najít stopy OOM killeru na svém serveru
dmesg -T | grep -iE 'killed process|out of memory' journalctl -k --since "2 days ago" | grep -i oom grep -i 'killed process' /var/log/kern.log systemctl status mariadb
“Out of memory: Killed process” znamená, že paměť došla celému serveru. “Memory cgroup out of memory” znamená, že byl dosažen limit cgroup, což se stává u limitů služeb systemd a v kontejnerech. Logika výběru oběti je v obou případech stejná. Pokud se databáze v noci restartuje “sama od sebe” a její chybový log neuvádí důvod, podívejte se nejdřív do dmesg. Celý postup hledání závad najdete v našem návodu na diagnostiku problémů s hostingem.
Jak ochránit MariaDB: oom_score_adj a systemd
Skóre se posouvá pomocí oom_score_adj, od -1000 do 1000. Jádro ke skóre přičte podíl celkové paměti: +500 znamená plus polovinu RAM (v cgroup plus polovinu limitu), -600 znamená minus 60 % a -1000 proces ze seznamu kandidátů úplně vyřadí. Aktuální hodnoty:
cat /proc/$(pidof mariadbd)/oom_score cat /proc/$(pidof mariadbd)/oom_score_adj choom -p $(pidof mariadbd)
Porovnávejte oom_score mezi procesy, ne s nulou: na současných jádrech má proces téměř bez paměti zhruba 666. Na stendu měla MariaDB 684, workery WordPressu 669-670.
Balíček MariaDB v Ubuntu 24.04 už obsahuje nápovědu: v /lib/systemd/system/mariadb.service je zakomentovaný řádek OOMScoreAdjust=-600 s komentářem vývojářů, že jádra rády zabíjejí mariadbd, protože je velký. Jinými slovy, ve výchozím stavu žádná ochrana není. Zapněte ji přes override:
sudo systemctl edit mariadb [Service] OOMScoreAdjust=-600 sudo systemctl edit php8.3-fpm [Service] OOMScoreAdjust=500 sudo systemctl restart mariadb php8.3-fpm
U MySQL se služba obvykle jmenuje mysql. Hodnota -1000 udělá z databáze nedotknutelný proces a únik paměti v samotné databázi pak zaplatí všechny ostatní procesy včetně sshd, takže můžete přijít o přístup k serveru. Proto doporučujeme pro databázi -600 až -900 a pro PHP-FPM kladnou hodnotu: správce poolu za zabitý worker jednoduše spustí nový.
Na stendu jsme oom_score_adj snížit nemohli: kontejneru chybí capability CAP_SYS_RESOURCE a zápis -1000 vrátil “Permission denied” (na běžném VPS jako root nebo přes systemd to funguje). Otestovali jsme proto druhou stranu a procesům PHP-FPM dali +500. Stejný požadavek na 150 MB:
Memory cgroup out of memory: Killed process 4307 (php-fpm8.3) total-vm:371772kB, anon-rss:80732kB, file-rss:8440kB, shmem-rss:19560kB, UID:33 pgtables:480kB oom_score_adj:500 WARNING: [pool cw18] child 4307 exited on signal 9 (SIGKILL) after 264.781050 seconds from start NOTICE: [pool cw18] child 8588 started
Tentokrát dostal těžký požadavek 502, nginx zapsal recv() failed (104: Connection reset by peer) a databáze s teplou cache si ničeho nevšimla: všech 60 požadavků na úvodní stránku dostalo 200. Výpočet je jednoduchý: jádro přičetlo k 108 MB workeru polovinu limitu (160 MB) a 268 MB převážilo 212 MB databáze.

První obranná linie: memory_limit a pm.max_children
Nejlepší je k OOM killeru vůbec nedojít. Stejný požadavek s memory_limit = 128M v poolu PHP-FPM skončil obyčejnou fatální chybou PHP za 0,35 s:
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2097152 bytes) in /srv/cw18/www/hog.php on line 4
Jeden požadavek se stavem 500, žádné zabité procesy a počítadlo oom_kill se nepohnulo. Nastavte proto memory_limit na to, co web opravdu potřebuje (pro WordPress obvykle 128-256 MB), ne na -1 nebo 1024M pro jistotu.
Druhou polovinou rovnice je počet workerů běžících současně. pm.max_children násobí paměť jednoho workeru a právě tady se nejčastěji chybuje, protože se sčítá RSS z top.
RSS, nebo PSS: kolik PHP-FPM worker doopravdy váží
smem -P php-fpm -c "pid command uss pss rss" PID Command USS PSS RSS 4307 php-fpm: pool cw18 3364 9948 38016 4309 php-fpm: pool cw18 4828 12067 41632 4306 php-fpm: pool cw18 5856 13039 42596 4308 php-fpm: pool cw18 9116 16456 46128
Každý worker ukazuje 38 až 46 MB RSS, dohromady 164 MB. Většina těchto stránek je však sdílená: OPcache a knihovny, které si každý worker počítá jako vlastní. PSS dělí sdílené stránky rovným dílem mezi procesy a součet PSS (50 MB) je skutečná spotřeba poolu. USS (3-9 MB) se uvolní, když konkrétní worker skončí. Bez smem najdete PSS v /proc/PID/smaps_rollup.
Praktické pravidlo: pm.max_children se rovná paměti, kterou můžete dát PHP, vydělené průměrným PSS workeru ve špičce, s rezervou pro těžké požadavky. Paměť pro PHP je RAM minus buffer pool databáze, minus ostatní služby, minus 15-20 % pro souborovou cache. Velikost buffer poolu určete podle objemu dat, jak popisujeme v návodu na optimalizaci databáze. Každá verze PHP má vlastní pool s vlastním nastavením, takže když změníte verzi PHP, zkontrolujte pm.max_children v novém poolu.
Kolik swapu server potřebuje
Na webovém serveru swap není pracovní paměť, ale rezerva. Jádro tam odkládá stránky, na které dlouho nikdo nesáhl, a dává vám pár minut na to, abyste si všimli úniku paměti dřív, než přijde OOM killer. Pokud server žije ve swapu pořád, web je pomalý a pomůže jen víc RAM nebo méně procesů.
| RAM serveru | Red Hat (RHEL 9) | Naše doporučení pro VPS s weby |
|---|---|---|
| do 2 GB | 2 × RAM | 1-2 GB |
| 2-8 GB | stejně jako RAM | 2 GB |
| 8-64 GB | alespoň 4 GB | 2-4 GB |
| nad 64 GB | podle zátěže, alespoň 4 GB | 4 GB |
Tabulka Red Hat platí pro libovolné systémy, proto pro databázový server doporučujeme méně: velký swap jen oddálí OOM killer, zatímco server pomalu přehazuje stránky z disku. Servery nehibernují, tento sloupec proto vynecháváme.
Jak vytvořit swapovací soubor
sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab swapon --show free -h
Na stendu jsme spustili první tři příkazy pro soubor 512 MB (mkswap odpověděl Setting up swapspace version 1, size = 512 MiB) a swapon jsme záměrně nespustili: stroj sdílí několik testů a swap působí na celý server. Proto článek neobsahuje měření rychlosti se swapem, jen ověřenou syntaxi. Na Btrfs a některých starších systémech se fallocate pro swap nehodí; soubor pak vytvořte příkazem dd if=/dev/zero of=/swapfile bs=1M count=2048. Pokud server teprve připravujete, přidejte swap spolu s dalšími kroky z našeho kontrolního seznamu nastavení VPS s Ubuntu 24.04.
swappiness: co to číslo znamená
Podle dokumentace jádra vm.swappiness určuje relativní cenu swapu ve srovnání se zahozením souborové cache: od 0 do 200, výchozí 60. Na testovacím stroji vrátil cat /proc/sys/vm/swappiness také 60.
- 0: jádro nezačne swapovat, dokud volné a souborové stránky neklesnou pod horní hranici (high watermark). Swap není vypnutý, stává se poslední rezervou.
- 10: naše doporučení pro databázový server. Jádro nejdřív uvolní souborovou cache a paměť MariaDB a PHP drží v RAM.
- 60: výchozí hodnota; swap je dražší než cache, ale používá se ochotně.
- 100: swap a souborová cache stojí stejně.
- nad 100: pro swap v paměti (zram, zswap); dokumentace uvádí jako příklad 133.
cat /proc/sys/vm/swappiness sudo sysctl vm.swappiness=10 echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
Příkaz sysctl platí do restartu, soubor v /etc/sysctl.d nastavení zachová trvale. Na stendu jsme je nespustili, protože jde o globální nastavení sdíleného stroje.
zram místo swapu na disku
zram vytvoří v RAM komprimované blokové zařízení, takže swap na něm funguje bez přístupu na disk. Dokumentace jádra počítá s kompresí zhruba 2:1 a zařízení zram větší než dvojnásobek RAM považuje za zbytečné. Pro VPS s 1-2 GB je to rozumná volba: v Ubuntu se zapíná balíčkem zram-tools nebo systemd-zram-generator a swappiness pro takový swap se nastavuje nad 100. zram jsme netestovali, protože jádro stendu tento modul nemá.
Pasti při počítání paměti
free -h na testovacím stroji:
total used free shared buff/cache available Mem: 7.8Gi 2.4Gi 1.8Gi 112Mi 4.2Gi 5.4Gi Swap: 0B 0B 0B
Sloupec free (1,8 GB) je paměť, kterou vůbec nic nepoužívá. Sloupec available (5,4 GB) je odhad jádra, kolik mohou nové procesy dostat bez swapování, včetně cache, kterou lze zahodit. Sledujte available: málo free při velkém buff/cache je normální chování Linuxu, ne nedostatek paměti.
Ověřili jsme to zvlášť: v cgroup s limitem 128 MB jsme dvakrát přečetli soubor 600 MB. Cache zaplnila celý limit (127 MB), jádro narazilo na limit 5 113krát a vyhodilo starší stránky, ale počítadlo oom_kill zůstalo na nule. Souborová cache OOM killer nespouští.
Třetí past jsme probrali výše: součet RSS z top nebo ps pro pool PHP-FPM nadsazuje spotřebu trojnásobně (164 MB oproti 50 MB PSS na stendu).
Příznak, příkaz, řešení
| Příznak | Co ukáže příkaz | Co dělat |
|---|---|---|
| Databáze se restartuje sama, v jejím logu není důvod | dmesg -T | grep -i 'killed process' ukáže mariadbd |
OOMScoreAdjust pro databázi, snížit pm.max_children a memory_limit |
| Občasné 502 na těžkých stránkách | dmesg ukáže zabitý php-fpm, log PHP-FPM píše “exited on signal 9” | Najít těžký skript, omezit memory_limit, přidat RAM |
| Chyba 500 “Allowed memory size exhausted” | Chybový log PHP | Optimalizovat skript nebo mírně zvýšit memory_limit |
| Web je pomalý, disk stále vytížený | vmstat 1: sloupce si a so stále nad nulou |
Málo RAM: méně workerů, menší buffer pool nebo VPS s větší pamětí |
| free ukazuje jen 100-200 MB volné paměti | available a buff/cache jsou velké | Nic, je to cache |
| Swap se používá, ale web je rychlý | vmstat 1: si a so jsou nulové |
Normální: leží tam nečinné stránky |
| Bez swapu, OOM při každé špičce | swapon --show nic nevypíše |
Swapovací soubor 1-2 GB a swappiness 10 |
Pokud nechcete swap, OOM killer a pooly PHP-FPM hlídat sami, web na WordPressu nebo jiném CMS může běžet na sdíleném hostingu: u hostingových tarifů RichHost nastavuje server, PHP a databáze tým hostingu a vy řešíte jen limity svého účtu.
Časté dotazy
Můžu swap na serveru úplně vypnout?
Můžete, ale pak jádro nemá kam odložit ani nečinné stránky a každá špička skončí zabitým procesem, jako v našem testu bez swapu. Malý swap s nízkým swappiness vyjde levněji než nouzový restart databáze.
Kolik RAM potřebuje VPS pro WordPress?
Sečtěte buffer pool databáze, PSS workeru vynásobené pm.max_children a zhruba 300-500 MB pro systém a souborovou cache. Na stendu měl čistý WordPress 10-16 MB PSS na worker; weby s těžkými pluginy váží víc, takže si ten svůj změřte. Pokud paměť chybí trvale, porovnejte ceny VPS serverů u tarifů s větší RAM.
Proč OOM killer nezabil proces, který paměť snědl?
Viníka nehledá, vybírá proces s nejvyšším skóre: rezidentní paměť, swap a tabulky stránek plus oom_score_adj. Velká databáze je téměř vždy těžší než jeden PHP worker.
Existuje OOM killer i na sdíleném hostingu?
Tam paměť serveru spravuje poskytovatel a web naráží na limity svého účtu: PHP memory_limit, počet procesů, chyba 508. Swap, swappiness ani oom_score_adj na sdíleném hostingu nastavovat nemusíte a ani nemůžete.



