RE:NODE

Návody11 min čtení

Memory leaky herního serveru: jak je najít a opravit

Jak rozeznat skutečný memory leak od růstu světa a plného heapu, najít plugin nebo mód v serverech na Javě, Lua, Unity a Source a mezitím leak zkrotit.

3 čtenáři

Herní server s memory leakem má spodní hranici paměti, která den po dni roste a nikdy neklesne, dokud se proces nerestartuje. Tento vzorec je jediný spolehlivý příznak. Paměť, která pár hodin stoupá a pak se ustálí, je cache nebo heap naplňující se na nastavenou velikost, a paměť, která roste s prozkoumaným světem, je růst, ne leak. Jakmile víš, že máš skutečný leak, najdi ho měřením uvnitř runtime - souhrnem heapu v Javě, collectgarbage("count") v Lua, monitory zdrojů ve FiveM, výpisy handlů v SourceModu - a vypínáním poloviny pluginů, dokud sklon nezmizí. Dokud není opraveno, plánovaný restart a určitá rezerva zabrání tomu, aby se z toho stal pád ve špičce.

Leak, růst, nebo cache: tři grafy, které vypadají stejně#

Graf paměti v panelu ukazuje stejnou stoupající čáru pro tři velmi odlišné situace. Jejich rozlišení je celý první krok.

VzorecCo vidíšCo to jeCo dělat
Naplnění a platóStoupá několik hodin po restartu, pak je rovnáHeap nebo cache dosahuje své velikostiNic; dimenzuj tarif podle plató
Skokový růstStoupá, když hráči prozkoumávají nebo staví, jinak je rovnáSvět se zvětšujeOčekávané; limity světa nebo víc paměti
Stoupající spodní hraniceNejnižší bod je každý den vyšší, bez ohledu na aktivituLeakNajít ho; do té doby restartovat

Test spočívá v čtení grafu přes dny, ne minuty, a pohledu na údolí - klidné hodiny, kdy nikdo není online. Skutečný leak stoupá i přes noc, nebo aspoň nikdy nevrátí, co vzal. Růst sleduje aktivitu hráčů: noc bez hráčů je rovná noc. Plný heap vystoupá jednou a zastaví se. Další tvary na stejném grafu popisuje čtení grafu zátěže serveru.

Dva systémy způsobují, že první vzorec vypadá jako leak pro lidi, kteří se s ním dosud nesetkali.

  • Java paměť nevrací. Server Minecraftu nebo Project Zomboid spuštěný s -Xmx6G dříve nebo později využije téměř 6 GB plus nějakou režii a zůstane tam. Garbage collector uvolňuje paměť uvnitř heapu; operačnímu systému ji vrací jen zřídka. To je normální a je to důvod, proč průvodce RAM pro Minecraft varuje před přidělením veškeré paměti Javě.
  • Servery na Unity a Unreal zvětšují své heapy po krocích a znovu je používají. Paměť serveru Valheim nebo Palworld po rušném večeru je vyšší než po klidném a nemusí klesnout zpět, aniž by cokoli unikalo.

Proč se z leaku stane pád#

Leak je pomalý problém s náhlým koncem. Každý den je spodní hranice vyšší, špička je vyšší a v nějakém okamžiku se špička rušného večera setká s limitem paměti tarifu.

Na hostingu s kontejnery jsou dva možné konce. Upstream Pterodactyl může serveru dovolit swap, který ho udrží naživu a zároveň strašlivě zpomalí. Na RE:NODE jádro zastaví kontejner na limitu a ten se čistě restartuje místo swapování - rychle se zotaví, ale z pohledu hry je to neuložené zastavení, takže se ztratí vše od posledního autosave. Všimne si toho i crash watcher: každé dvě minuty kontroluje servery, jejichž uptime se vrátil zpět, ignoruje restarty, o které jsi požádal, a po třech nevyžádaných restartech za hodinu zveřejní na stránce serveru varování a automaticky otevře tiket. Server s leakem takové frekvence obvykle nedosáhne, protože leak se plní dny, ale server s leakem, který padá dokola u svého stropu, ano. Podrobnosti jsou v článku proč se tvůj herní server pořád restartuje a stranu jádra v článku Linuxový swap a OOM killer.

Restartspodní mez se vynulujeDny uptimespodní mez rosteRušný večeršpička dosáhne limituZastavení OOMbez uloženíZtracený postupod posledního autosave
Jak pomalý leak vede ke ztracenému večeru

Správné měření#

Než cokoli obviníš, změř čísla.

  1. Restartuj server a poznamenej si paměť poté, co se dokončilo načítání a ustálila se - pět nebo deset minut.
  2. Zapisuj spodní hranici denně po tři až pět dní: nejnižší hodnotu v klidných hodinách.
  3. Poznamenej si, co se změnilo v těch dnech: hráči, nové stavby, nové pluginy, události.
  4. Spočítej sklon. 150 MB denně na tarifu 6 GB ti dává měsíc; 800 MB denně týden.

Pokud máš na stroji shell, rezidentní paměť procesu je v /proc:

bash
$ grep VmRSS /proc/$(pgrep -f valheim_server)/statusVmRSS:   3145728 kB

Jedno upozornění k číslům z kontejneru. Účtování paměti kontejneru může zahrnovat souborovou cache - stránky herních souborů, které jádro drží v paměti, protože byly nedávno čtené. Tato cache je uvolnitelná a není to leak, i když se může objevit v surových číslech cgroup. Lepším měřítkem je vlastní rezidentní paměť procesu nebo vlastní hlášení runtime.

Hledání v serverech na Javě#

Minecraft a Project Zomboid běží na JVM a Java má nejlepší nástroje ze všech herních runtime.

Otázka v Javě nezní „používá proces hodně“ - bude používat svůj heap - ale „roste živá data po garbage collection“. Na Paperu na to odpoví spark zevnitř hry:

code
/spark heapsummary/spark gc

heapsummary vypíše třídy držící nejvíc paměti podle počtu instancí a velikosti. Udělej jeden krátce po restartu a druhý o den později. Třída, jejíž počet vyrostl z tisíců na miliony a má v sobě název balíčku pluginu, je tvůj podezřelý. /spark gc ukazuje chování garbage collection; heap, který je těsně po každé sběrné operaci téměř plný, znamená, že živá množina vyrostla. Čtení výstupu pokrývá průvodce profilerem spark.

Mimo hru odvedou stejnou práci nástroje samotného JDK:

bash
$ jcmd $(pgrep -f paper.jar) GC.class_histogram | head -25$ jstat -gcutil $(pgrep -f paper.jar) 10s

Histogram jsou stejné informace jako heapsummary. jstat -gcutil každých deset sekund vypíše, jak je plná každá generace heapu; sleduj sloupec staré generace hned po plných sběrech. Pokud se v průběhu hodin plíží nahoru, živá data rostou. Úplný heap dump (jcmd <pid> GC.heap_dump /tmp/heap.hprof) lze otevřít v Eclipse MAT, aby bylo vidět, co objekty drží, ale pozastaví server a zapíše soubor o velikosti heapu - pořiď ho v klidné době.

Obvyklými viníky v Javě jsou pluginy, které si drží odkazy na hráče, světy nebo chunky i poté, co se uvolnily: mapy pro každého hráče, které se při odchodu nikdy nečistí, listener, který ukládá každou událost, cache bez limitu velikosti. Pluginy načítající chunky a některé renderery mapy světa drží v paměti chunky, které by server jinak uvolnil. V histogramu se projeví jako rostoucí objekty světa nebo chunků.

Hledání v Lua: Garry's Mod, FiveM, Don't Starve Together#

Lua ti prozradí velikost svého heapu. V Garry's Modu z konzole serveru:

code
lua_run print(collectgarbage("count"))

Číslo jsou kilobajty využité Lua stavem serveru. Poznamenej si ho po restartu, po několika hodinách a po dni. Pokud stabilně roste, nějaký addon ukládá tabulky, které nikdy neuvolní - typicky tabulky pro hráče indexované entitou hráče, časovače vytvářené při každém spawnu a nikdy neodstraněné, nebo opakovaně přidávané hooky. Odebírání addonů po polovinách a sledování tohoto čísla několik hodin zúží výběr mnohem rychleji než sledování celkové paměti procesu.

FiveM ukazuje paměť po zdrojích. V konzoli F8 klienta otevře resmon 1 monitor zdrojů s časem CPU a pamětí každého běžícího zdroje, jak ho vidí tento klient, a vlastní příkaz serveru profiler zaznamenává serverové náklady zdrojů. Zdroj, jehož sloupec paměti stabilně stoupá, zatímco ostatní stojí, je leak. Čtení popisuje výkon serveru FiveM a resmon.

Don't Starve Together a další hry s módy v Lua se řídí stejným principem: paměť Lua patří módům, takže leak je téměř vždy mód, který ukládá stav na hráče, entitu nebo den a nikdy ho nečistí.

Hledání v serverech na Unity, Unreal a Source#

Hry na Unity

Valheim, Rust, 7 Days to Die a Unturned běží na Unity, obvykle s runtime Mono pro módy. Jejich spravovaný heap roste a zřídka se zmenšuje, takže vysoké, ale rovné číslo je normální. Leaky tu pocházejí hlavně z módů: plugin BepInEx ve Valheimu, plugin Oxide nebo Carbon v Rustu, mód Harmony v 7 Days to Die. Rust ti v konzoli dává několik nástrojů - gc.collect vynutí sběr a pluginové frameworky hlásí časy hooků po pluginech, což ukáže na zlobící pluginy - ale účtování paměti po pluginech je omezené. Spolehlivou metodou je půlení.

Některé hry na Unity mají i růst řízený světem, který vypadá jako leak: počty entit v Rustu rostou během wipe, jak hráči stavějí, a paměť 7 Days to Die roste s počtem načtených regionů. Než obviníš mód, porovnej s počty entit nebo regionů.

Hry na Unreal Engine

Palworld, ARK a další servery na Unreal spravují nativní paměť. Leaky tu bývají v samotné hře, ne v módech, a jedinou skutečnou opravou jsou záplaty od vývojářů. Raná vydání Palworldu byla známým příkladem: paměť rostla s uptime až do restartu. Pokud tvůj server na Unreal vykazuje stoupající spodní hranici bez nainstalovaných módů, zkontroluj poznámky k záplatám od vývojáře a hlášení komunity, než strávíš čas půlením, a leak zkroť restarty. Konkrétně tuto hru pokrývá paměť serveru Palworld.

Source a SourceMod

SourceMod sleduje handly - odkazy, které pluginy drží na časovače, soubory, databázové dotazy a datové struktury. Plugin, který handly otevírá a nikdy nezavírá, způsobuje leak, a SourceMod si toho při dosažení prahu všimne, zapíše do svého chybového logu MEMORY LEAK DETECTED IN PLUGIN s názvem souboru pluginu a plugin pak uvolní. Počty handlů můžeš prohlédnout i přímo:

code
sm_dump_handles handles.txt

Výpis uvádí handly podle vlastnícího pluginu. Pořiď jeden po restartu a druhý o den později; plugin, jehož počet stále roste, je leak. Správu pluginů pokrývá pluginy SourceMod pro Team Fortress 2.

Půlení, když nástroje nikam neukazují#

Když runtime nedokáže paměť přiřadit komponentě, rozděl a měř:

  1. Udělej zálohu serveru, konfigurací a dat pluginů.
  2. Vypni polovinu pluginů nebo módů, které lze bezpečně odebrat bez poškození uložených světů. Obsahové módy, na kterých svět závisí, ponech; ty testuj nakonec, na kopii.
  3. Nech běžet celý den a zapiš spodní hranici ve stejnou klidnou hodinu.
  4. Pokud sklon zmizel, leak je v polovině, kterou jsi odebral; vrať ji a odeber druhou. Pokud zůstává, je v polovině, která pořád běží.
  5. Opakuj, dokud nezbude jediný plugin. Dvacet pluginů vyžaduje asi pět kol - pracovní týden, protože každý test potřebuje den.

To je pomalé, takže to pokud možno dělej na kopii. Provoz testovacího serveru vedle produkčního popisuje testovací server vedle produkce a stejnou metodu půlení aplikovanou na pády je v článku co dělat, když aktualizace módu něco rozbije. Jakmile máš viníka, zkontroluj aktualizaci, nahlas ho autorovi s čísly před a po, nebo ho nahraď.

Zkrocení leaku, dokud není opravený#

Většinu leaků neopravuješ ty; nakonec je opraví autor pluginu nebo vývojář hry. Mezitím:

  • Naplánuj restart dřív, než spodní hranice dosáhne nebezpečí. Pokud spodní hranice roste o 500 MB denně a máš 2 GB rezervy nad normální špičkou, stačí restart každé dva dny - nepotřebuješ ho každou noc. Volbu četnosti podle grafu místo zvyku vysvětluje rozvrhy restartů, které pomáhají.
  • Před každým restartem ulož. Dej příkaz hry pro uložení minutu před restart ve stejném rozvrhu. Restart, který nejdřív uloží, nikoho nic nestojí.
  • Zkrať interval autosave, dokud leak existuje, aby neplánované zastavení u stropu stálo minuty. Nastavení pro jednotlivé hry najdeš v článku intervaly autosave herních serverů.
  • Měj rezervu. Server, jehož normální špička je pár stovek megabajtů od limitu, nemá žádnou rezervu pro leak. Přechod na vyšší tarif na RE:NODE změní limit na serveru, který už máš, bez nového sestavení.

Na RE:NODE záložka Schedules spouští seřazené úlohy se zpožděním - příkaz konzole, pak akce napájení - podle výrazu cron, takže „ulož, počkej minutu, restartuj“ každou druhou noc v 05:00 je jeden rozvrh.

FAQ#

Je normální, že RAM mého serveru pořád roste?

Několik hodin po restartu ano - heapy a cache se plní. Poté by paměť měla sledovat aktivitu hráčů a velikost světa. Spodní hranice, která roste každý den, i když nikdo nehraje, je leak.

Proč můj server Minecraftu využívá všechnu RAM, kterou jsem mu dal?

Protože Java plní svůj heap až do -Xmx a zřídka vrací paměť operačnímu systému. To není leak. Než se začneš znepokojovat, zkontroluj pomocí heapsummary ze sparku nebo jstat, jestli živá data heapu po garbage collection rostou.

Opraví memory leak denní restart?

Zkrotí ho, neopraví. Leak se s procesem vynuluje a začne znovu. Restart použij k tomu, aby server zůstal daleko od limitu, zatímco hledáš a odstraňuješ příčinu.

Může víc RAM vyřešit memory leak?

Koupí čas úměrný přidané paměti dělené denním růstem. To může být správná krátkodobá odpověď, ale leak nakonec nový limit stejně dosáhne, pokud server dřív něco nerestartuje.

Jak zjistím, který plugin leakuje paměť?

Nejdřív použij nástroje samotného runtime - spark nebo jcmd pro Javu, collectgarbage("count") pro Lua, resmon pro FiveM, sm_dump_handles pro SourceMod. Pokud neukážou na jediný plugin, vypínej pluginy po polovinách a pokaždé po dobu jednoho dne měř spodní hranici paměti.


Komentáře

Zcela anonymně: žádný účet, žádný e-mail, žádné cookie. Ukládáme jen jméno, které napíšeš, text a čas - nic dalšího. Počet odkazů je omezený a značkování se nevykresluje.

0/2000