.NET mi spíš připomíná další kámen na cestě ke Smalltalku :)
Přetékání bufferů, zápisy mimo hranice pole, resource leaks, chyby pointerové aritmetiky, absence výjimek u frameworků. Managed jazyky samy o sobě tohle řeší.
Hmm, takže za problémy může Céčko, protože ve slušně napsaném C++ nic takového nenastává :) C++ totiž tohle také řeší (sice dovoluje programátorovi tu kontrolu obejít, ale když programátor není prase, tak to řeší).
Nemluvě o možnosti matematicky prokázat nějaké požadované vlastnosti SW.
Něco jako BitC? Mimochodem .NET umí formální verifikaci?
proč tedy nemá preemptivní kernel
Protože to nepotřebuje?
proč kernel 2.0 pořád neměl threading
Ze stejného důvodu, proč Windows dodnes nemají fork.
proč je I/O pořád řešené tak příšerně
To jako proč se celá paměť používá jako cache?
proč existuje hrůza vzaná OOM Killer?
Aby, když se zblázní aplikace, se ten stroj neuswapoval k smrti, jako to udělají Windows.
Overcommitting lze samozřejmě vypnout. Jestli ti vadí OOM killer, tak tím se ho zbavíš (resp. pořád tam bude, ale nikdy se neaktivuje). Druhá možnost je aktivovat swapd a nechat dynamicky zvětšovat swap.
Důvodem overcommittingu není ani tak fork a COW, ale to, že linuxové knihovny (hlavně libc) kvůli rychlosti alokují paměť po velkých kusech. Pokud se ti ani to nelíbí, není problém to přenastavit v libc.
Dalším zábavným side effectem je to, že autoři apikací neošetřují nedostatek paměti, protože vědí, že to stejně skončí OOM Killerem, a ne selháním alokace.
To je fakt nebo mýtus? Pokud se vypne overcommitting, tak samozřejmě může selhat i alokace.
Bohužel pak celem záhy dojde paměť, protože Linux je mimořádně žravý.
Což je právě vlastnost glibc, kterou lze při kompilaci změnit.
Po jak velkých kusech glibc alokuje paměť, že to vede k nutnosti overcomittingu?
Většinou po velkých mocninách dvojky a naalokovanou paměť potom půlí (a čtvrtí a osminuje atd.) při přidělování mallocem. Ano, je to obrovské plýtvání, ale je to velmi rychlé, minimálně to fragmentuje a ve spojení s overcommittingem to celkem dobře funguje.
Overcommitting prakticky nikdo nevypíná, protože by mu rychle došla paměť.
Na routerech se vypíná běžně, právě aby nemohl zasáhnout OOM killer a router rozbít. S docházením paměti tam většinou nejsou problémy a to routery mívají velmi málo paměti.
Používání forku bohužel nezměníte nastavením při kompilaci. To, že použití forku vede k velké spotřebě paměti, je platný argument.
I tomu by šlo zabránit, stačilo by fork + exec dvojku upravit na clone(CLONE_VM) + exec (stačí přidat ptrace na spuštění a máte windowsí CreateProcess).
Velké mocniny dvojky jsou pěkný výraz. Můžeme to zkusit znovu. Po jak velkých kusech glibc alokuje paměť, že to vede k nutnosti overcomittingu?
To nelze říct přesně, ten algoritmus výpočtu změny velikosti při volání sbrk je poměrně složitý a záleží na velikosti požadované paměti, paměti již alokované a i nějakých statistikách. Občas nabere zbytečně moc paměti, třeba i více než dvojnásobek toho, co se reálně využije.
Routery jsou příklad na nic. Sám dobře víte, že počet procesů, které na routeru běží, se prakticky nemění. Nesnese to srovnání s běžným desktopem, na kterém běží obrovská spousta aplikací, a paměťové nároky se každou chvíli mění.
No a u desktopu zase není nejmenší důvod nemít zapnutý overcommitting (víte, kolik by sežraly jen KDE kvůli COW v knihovnách? A víte, že ve Windows to taky žere?), tedy i buď swapd (což je obdoba windowsího automaticky se rozšiřujícího swapu ve FS, což ale bez rozumného horního limitu znamená nebezpečí uswapování stroje) nebo OOM killer.
Jinými slovy vykydání chléva linuxového memory managementu se nechystá. Linux bude dál aplikacím slibovat paměť, kterou nemá, a když pak dojde na lámání chleba, tak bude sofistikovaně odstřelovat procesy. K tomu budou aplikace pro jistotu ještě lhát o tom, kolik chtějí paměti, protože přece mají overcomitting. To je fakt humus. Nechápu, jak někdo může používat takový hnus, a jakkoliv kritizovat memory managemet Windows, který je zjevně výrazně lepší.
Hmm, takže Windows aplikacím řeknou, když není paměť, a aplikace buď spadne, skončí nebo to zkusí znovu. První a druhá možnost je obdobná OOM killeru s tím rozdílem, že spadne/skončí něco, co zrovna potřebuji (co jiného by zrovna v tu chvíli alokovalo paměť, že), zatímco OOM killer zabije něco, co velmi pravděpodobně nepotřebuji (protože ta aplikace už dlouho nic nedělala, má vysoký nice ap. - ta kritéria jsou dost sofistikovaná). Při té třetí, nejlepší možnosti (z hlediska kvality programu) naproti tomu ani nespustím Správce procesů, abych mohl nějakou nepotřebnou aplikaci zabít, případně se ani nepřihlásím, protože na to nebude paměť a běžící kvalitně napsané aplikace neskončí, ale budou čekat, až nějaká paměť bude. Děkuji, raději ten OOM killer.
S tím výkonem a fragmentací mi to pořád není jasná. Pokud aplikace chce 4kB paměti, a glibc požádá řekněme o 1MB, tak stejně paměť v tu chvíli nedostane. V nejlepším případě paměť dostane ve chvíli, kdy aplikace poprvé přistoupí ke stránce, kterou údajně dostala. Nijak se to ale neprojeví na fragmentaci fyzické paměti. Jediné, co může dojít vylepšení, je fragmentace adresního prostoru aplikace. Ovšem jen za předpokladu, že adresní prostor rozšiřuje ještě nějakým dalším způsobem (třeba mmap). A i to se nakonec dá řešit jinak a lépe.
Ano, jde o fragmentaci adresního prostoru aplikace a smyslem je to, že glibc má strom alokací (které odpovídají nějakému velkému naalokovanému úseku a v něm půlce, půlce té půlce atd.), díky čemuž alokace a dealokace v adresním prostoru aplikace jsou velmi rychlé (je málo stromů, protože se alokuje po velkých kusech) a minimálně fragmentují (nejsou žádné sofistikované velikosti, jen mocniny dvojky a bloky v rámci jednoho stromu mohou přesahovat přes hranici stránky)
Sofistikovaný algoritmus na nedeterminisatické odstřelování procesů je moc pěkná věc. Když chcete, aby pro váš proces malloc opravdu fungoval jak má, můžete ho imunizovat proti OOM Killeru. On potom systém odstřelí něco jiného.
Aplikace sama se, pokud neběží pod rootem, nemůže imunizovat. Jinak pořád je to lepší stav, než když všechny aplikace čekají na paměť, protože malloc vrací nulu, a tak ani nelze spustit Správce procesů, kterým by šla paměť uvolnit - prostě takový jednoduše proveditelný deadlock přímo v návrhu systému (docela se divím, že toho ještě žádný vir nevyužil).
Linusovi nemá smysl psát. Zavedl memory management Linuxu do bažiny, a to díky tomu, že na začátku nebyl schopný udělat slušný návrh.
Mě návrh používající overcommitting a OOM killer přijde velmi slušný. Prosím nezapomínej, že Linus stavěl na POSIXu, tudíž si nemohl dovolit ignorovat fork a worker processy a s toho plynoucí problém se zabranou a nevyužitou pamětí, pokud by se overcommitting nepoužíval. Jak jsem ale psal výše, v případě, že dojde paměť, tak je úplně jedno, jestli overcommitting byl nebo nebyl použit - něco stejně spadne, případně bez overcommittingu to může dopadnou ještě hůř, celý systém se dostane do paměťového deadlocku.
Když aplikaci ve Windows selže alokace, může s tím ještě řadu věcí dělat. Například danou akci prostě odmítnout. Zkuste si to u MS SQL Serveru, MS Exchange, Oracle a dalších. Prostě dostanete hlášku typu "nelze alokovat dalšách 123456 bytů", a operace selže. Není důvod, aby kvůli tomu jakýkoliv proces padal.
Ale pouze v případě, že je ještě dost paměti to hlášku vůbec sestavit.
Pro management aplikací nepotřebujete pouštět Task Manager. Jistě víte, že není problém zastavit servis nebo odstřelit proces ze vzdáleného stroje.
Což má některé zásadní nevýhody, například to hodně blbě budu dělat na notebooku bez připojení k síti nebo když máte jen jeden počítač. Stejně tak povolit tam přístup přes síť na takovou službu je potenciální bezpečnostní díra.
Také není problém nastavit procesu, nebo sadě více aplikací, limit na zdroje.
Limity na zdroje umí i Linux (ulimit).
A aplikace může reagovat na selhání alokace mimo jiné zmenšením interních bufferů apod.
Tím se (pravděpodobně jen dočasně) zachrání ta aplikace, ale ne celý systém.
Na stroji běží věci, které tam běžet mají. OS je tam od toho, aby aplikace běžel, a ne aby "sofistikovaně" vybíral, které z nich "zřejmě" potřebujete.
Pořád jsem raději, když v nouzových případech (jako je nedostatek paměti) poběží to, co v tu chvíli zřejmě potřebuji, než to, co v tu chvíli zřejmě nepotřebuji, ale jinak to tam běží, protože se to běžně používá (třeba Samba, Apache, SQL server ap.). Zřejmě ti nějak nedochází, že nedostatek paměti je extrémní problém a systém si s tím musí nějak poradit - pokud možno tak, aby se z toho dostal, i kdyby aplikace odmítaly spolupracovat.
Když jsme u DoS pomocí vyčerpání paměti, tak to je věc, která u Linuxu skončí tím, že OOM Killer postřílí, co mu přijde pod ruku. Takže váš škodící program bude mít paměti velkou spoustu, a vše ostatní umře
Jedna z věcí, kterou OOM killer bere v úvahu, je také sežraná paměť. Pokud nějaká aplikace žere paměť jako divá, dokonce tak, že má víc, než ostatní aplikace dohromady, tak ji OOM killer sestřelí, protože evidentně s ní nebude něco v pořádku (shell ani jiné utility tolik nesežerou). Jinak samozřejmě root a jeho aplikace mají právo veta (případně mají k dispozici mlock a mlockall, takže mohou dojít do stavu, že naalokovanou paměť budou mít, ať se děje, co se děje), tam by cesta ke shození systému byla. Ale když už něco získá práva roota, tak nemá cenu shazovat systém na vyžrání paměti :)
Kdyby Linux měl od začátku threading a lepší alternativu k fork/exec, nebyl by overcomitting třeba.
Mohl bych vědět, co POSIXového měl Linus použít místo fork/exec?
Jakýkoliv vzdálený přístup ke stroji je potenciální bezpečnostní díra, takže to nepovažuji za argument.
Pokud nejde o šifrované a klíčem nebo heslem podepsané spojení, je to obří díra. Pokud je to šifrované a klíčem nebo heslem podepsané, potřebuje to paměť (minimálně na šifrovací klíč), která v tom okamžiku není, takže to nemůže fungovat.
Musíme si vyjasnit důležitou věc. Na Windows když dojde paměť, tak to znamená, že aplikace nedostane DALŠÍ paměť. Co má alokováno, s tím může fungovat. Když další alokace neprojde, může se podle toho zařídit. Není co zachraňovat - jde o stav jako každý jiný.
Z hlediska aplikace to je celkem normální stav. Z hlediska systému ne - nejsou zdroje pro nové a to ani servisní aplikace, systém se dostal do slepé uličky a pokud se nějaký proces neráčí ukončit (nebo spadnout, pokud neošetřuje alokace) nebo alespoň uvolnit nějakou paměť, tak se z ní už ani nedostane. Normální stav je to jen v případě, že není důvod spouštět nové aplikace ani alokovat další paměť, což ale u běžné práce ani u běžného server není téměř nikdy - na druhou stranu je to důvod, proč se na routerech overcommitting nepoužívá.
Obhajujete zjevně špatný model jen proto, že je použitý v Linuxu?
Ne, obhajuji zjevně špatný model jen proto, že pokud dojde k závažnému problému (což z hlediska systému nedostatek paměti je, to doufám chápe i MS) funguje lépe, než ten dokonalý model ve Windows. Jinak pokud ti vadí, tak Linux má tu krásnou vlastnost, že není vůbec žádný problém to změnit - na rozdíl od Windows :)