Prosim, podla vzoru diskusii k predchadzajucim clankom aby ste sa najprv zamysleli ci Javu pouzivate viac ako 5 rokov a tunovali ste uz web server so zatazou viac ako 200.000 session za den, ci nam mate co nove povedat. Tieto clanky su neskutocne "advanced topic" a preto prosim nemiesat s beznym pouzivanim Javy kedy nic, z toho uvedeneho v tomto clanku nepotrebujete.
Pod minulymi clankami sa sustredilo take mnozstvo hluposti, obzvlast od ludi ktory Javu videli akurat ako sample na web stranke ze sa na to nedalo ani reagovat.
Myslim ze cela snaha vsetkych tvorcov Garbage Collectorov je aby vsetko fungovalo bez akehokolvek zasahu pokial mozno optimalne bez specialneho nastavovania a porozumenia detailov prislusneho GC.
Bezny programator sa musi riadit uplne inymi pravidlami optimalizacie kodu ako je GC. Najlepsie na tom je ze vacsina frameworkov, specialne napriklad Spring Vas nuti k optimalne napisanemu kodu bez toho aby ste robili akukolvek specialnu GC oriented optimalizaciu.
DOPREDU DAKUJEM
Neviem ci si si cital diskusiu pod minulymi clankami. Mi to pripadalo ako keby kazdy, najlepsie ten kto zacina robit s Javou riesil ako prve vykonnost a nastavovanie GC. Namiesto toho aby zacali s OOP, kniznicami, frameworkami sa kazdy trapi nad tym ako to ten GC zle/dobre riesi a ako je GC idea uplne zla.
GC urcite neni spatny, je to jen dalsi technologie, ktera ulehcuje programatorum vetsiny typu aplikaci (vyjimky se najdou) vyvoj. Neni vhodny pro vsechny aplikace, ale pro mnohe ano - to ovsem plati pro jakykoli nastroj v IT :-)
Ovsem GC sam o sobe nevi vsechno, stejne jako prekladac nevi vsechno - oba nastroje si sice delaji nejakou analyzu, ovsem prave algoritmy GC jsou zalozeny na heuristice: to co jsme dobre udelali pro n aplikaci bude pravdepodobne fungovat i pro n+1 aplikaci. Ve chvili, kdy tomu tak neni, nastupuje ladeni GC, coz ovsem muze byt jednodussi, nez vymysleni lepsich algoritmu ci jejich efektivnejsi implementace.
Neco podobneho jste urcite zazil s ORM frameworky: na jednodussi veci postacuji automaticky generovane SQL prikazy vychazejici primo z ORM (hierarchie objektu a jejich vazeb), ovsem pro aspon trosku vetsi databaze ci pro slozitejsi schemata proste na radu musi prijit borec s dobrou znalosti dane databaze (a samozrejme SQL) a zacit optimalizovat.
Ja plne suhlasim. Len je to topic pre pokrocilych pouzivatelov/adminov, nie nieco na clovek bezne siaha pri programovani swingovej aplikacie. Narazal som iba na predchadzajuce diskusie kde vela C/C++ koderov rovno odpisali GC ze to nemoze byt nikdy dobre/lepsie ako rucne napisany kod a podobne.
Ja si pamatam ze som prvy krat ladil GC na WebLogic-ovom servri s JRockitovym JVM a poviem vam ze o tom GC bolo na nete menej informacii ako je v tomto clanku. Od vtedy som to robil asi iba 2 krat z toho iba raz na Sun JVM. A nie ze by som malo instaloval. Za posledne roky si ale napatam ze by som musel na niecom ladit GC. Co uz clovek odladi na 8GB RAM a 4imi velkymi aplikaciami v servri pokial tam naozaj nema memory leak. Prevazne sa jednalo o komercne Webove servre a vsetky fungovali postacujuco.
Vdaka za clanky, su iste zaujimave a ja som ani clanky samotne nekritizoval. Len som chcel zabranit "zvlastnej" diskusii pod nimi.
Teraz som tu sice za idiota ja, ale to prekusnem ;-).
Nojo, to jsem minule a predminule tak trosku ocekaval, ze se ozvou lidi od C/C++, tomu se moc neda vyhnout, i kdyz mam cim dal tim vice pocit, ze se jedna o jazyky vhodne pro naprosto odlisne veci (zpocatku to mozna tak nevypadalo, kdyz se Sun snazil Javu prosazovat na desktopu a webu).
Fakt je, ze jsem si s tuningem GC posledni dobou hral casteji nez obvykle, predevsim kvuli snaze dostat co nejlepsi vysledky pri behu JVM na vicejadrovych masinach a take na opacne strane spektra - potreboval jsem (coz se kupodivu podarilo) rozjet Eclipse na stroji s 256 MB RAM tak, aby neswapoval a soucasne se v nem dalo rozumne pracovat na SE aplikacich. Tech 256 MB je skutecne na hrane pouzitelnosti, ale jde to: Eclipse+Tomcat+nekolik nasazenych aplikaci na Tomcatu.
Nechci vyvolávat flame, ale řeknu to na rovinu, jak to vidím. Protože jste srandovní.
Vaší neschopnost pořádně programovat v C/C++ si kompenzujete s GC a HotSpotem. Výsledkem dostáváte program, který běží únosně dlouhou dobu, pokud nedělá nic náročného. Když se nároky zvednou, tak děláte jediné, co můžete - kupujete víc hw a ladíte parametry GC. A přitom si dobře napsaný program v C/C++ válí šunky, zatímco vy ladíte parametry GC a tváříte se, jako kdyby to byl jen váš kód, který ždímá z hw maximum. A přitom ho ždímá HotSpot a GC jako daň za používání Javy.
A proto mi připadáte srandovní, když tu předvádíte šou, jako kdybyste byli odborníci na náročné výpočty. Např. od Pala - 200 000 sessions za den. A co? 2,3 session za sekundu. A jaký objem dat představuje jedna session a jaká je náročnost jejich výpočtu? To už se neřekne, ale zato už se hbitě vytváří dojem specialisty na vysoce zatížené servery. Čímpak jsou asi zatížené? :)
Psáno podle vlastních zkušeností s Java "programátory". Čest vyjímkám. Neberte si to zle, ale občas byste potřebovali probrat do reality skutečně náročných aplikací, co to znamená programovat. Protože dneska už se za programátora prohlašuje kde kdo, "komu to procesor upočítá "session" dřív, než bude voda kafe".
Jen abych to uvedl do kontextu - ja neprogramuji aplikace v Jave, ja spoluvytvarim OpenJDK, coz je kombinace assembleru (velmi malo), C++ a samozrejme Javy (knihovni cast). Takze si dovolim tvrdit, ze o C/C++ neco malo vim (ovsem zdrojaky OpenJDK jsou co se tyce C++ pomerne "defenzivni", je to takove jednodussi C++)
Jinak jeste doplnim - GC je pomucka a to dost dobra pomucka a prakticky vsichni programatori (krome naprosto zanedbatelneho 0.0*1%) pouzivaji pomucky vytvorene bud jimi nebo nekym jinym - minimalne assembler a linker, kdyz uz nic jineho (ve skutecnosti toho je mnohem mnohem vic). A IMHO je dobre vedet, jak tato pomucka pracuje a kdy/jak se daji nastavit jeji parametry.
No, ony typické možnosti projektu vypadají takto:
1) Uděláme to v C/C++, náklady na programováni 2.000.000,-, náklady na HW 100.000,-
2) Uděláme to v Javě (nebo .NET), náklady na programování 1.000.000,- náklady na HW 200.000,-
To není o neschopnosti ;-)
A když vidím, jakým způsobem rozpočítáváte session, tak bych řekl, že jste od reality náročných aplikací na hony vzdálen ;-)
To je prece uplne fuk ;).
Tomu panovi nejde o neco tak mrzkeho jako jsou penize, prosim vas.
On to chce mit nejlip! Penize se do toho jenom zbytecne motaji.
A javisti ? To jsou hrozny nemehla a jdou jenom po penezich, kdyz
jsou dnes javisti tak dobre placeni.
Je to proste celkove spiknuti spatnych programatoru a dokonce maji
drzost tem vybornym (rozumnej c/c++ programatorum) tvrdit neco
jineho.
Skandal!
Celou dobu se snažím napsat knihovnu, se kterou se budou ty nejzákladnější věci psát podobně rychle jako v Javě. Docela se mi to daří, ale vždycky to bude mít své specifika. Nicméně z toho celého výzkumu mám jeden dost významný pocit. Síla Javy je hlavně v knihovnách a v jednom silném hráči, který tomu dává nějakou úroveň. C++ je džungle, kde neexistuje silný hráč, kde každý má vlastní způsob práce, a kde jeden programátor bez dobré znalosti knihovem třetích stran, nemá prakticky šanci nic levně naprogramovat. A v případě těch knihoven se zase stává plně závislý na těch knihovnách a není schopen programovat jinak.
Když si představím, že bych současný projekt psal místo v C++ v Javě, nemyslím si, že bych byl o polovinu rychlejší, abych svému zaměstnavateli ušetřil tolik peněz. GC mi mou práci rozhodně neurychlí, protože automatický úklid prostředků už mám samozřejmě dávno vyřešen a jen těch pár případů nějakých cyklických referenci mi opravdu nezvedne dobu vývoje na dvojnásobek.
Ale používejte si co chcete :-)
Ad první odstavec: Ano, to je pravda, tesat do kamene :-)
A rovnou z toho můžeme odvodit odpověď na druhý odstavec: Ano, Tys možná ten současný projekt nenapsal o moc pomaleji než v Javě. Ale když by ses se svým zaměstnavatelem nepohodl / přejelo Tě auto a musel ho přebírat někdo jiný, tak do bude setsakra drahé, než se ten někdo jiný naučí Tvoje knihovny, pokud rovnou nezačne předělávat projekt na svoje oblíbené knihovny :-)
Nehledě na to, že v Javě jsou (relativně standardizované) prostředky, jak řešit takové věci jako distribuované transakce, messaging mezi komponentami, deklarativní validaci atp. rozhodně to není jen o GC, to je nesmyslné zjednodušení.
Předpokládám, že i na Javaprojektu vznikne mnoho vlastních knihoven, ale chápu jak je to myšleno. Pokud jde o hledání té základní úrovně práce, tak většina lidí nakonec je donucena pracovat v zastaralém a překomplikovaném a hlavně pomalém STL. Pokud se už programátoři na něčem shodnou, tak maximálně boostu a to ne všichni (já jsem většinou proti, protože mi to připomíná svým stylem STL II, a nejde jen o výkon, třeba o programátorský styl).
Nicméně, každý manager by neměl k jednomu projektu pouštět jen jednoho člověka a dbát na předávání know-how dalším generacím. Pak nic takového jako přepisování knihoven nehrozí, nebo jen minimálně.
> Vaší neschopnost pořádně programovat v C/C++...
Dalsi ktery povazuje vyuzivani existujicich nastroju za neschopnost? Kde se to porad bere? Je snad programovani v c++ neschopnost psat to ve strojaku?
> přitom ho ždímá HotSpot a GC
Ten HotSpot muze proste z principu udelat lepsi optimalizace nez takove gcc nad c++. S ohledem na podil kodu, ktery je v typicke aplikaci kriticky bych to nevidel jednoznacne jako ztratu.
To ze GC ma nejak vetsi naroky nez malloc/free je tak zazrany mytus, ze snad bude muset tahle generace vymrit aby od toho byl pokoj...
No nevim, ale kazdopadne se hodi znat moznost nastavi velikost pameti Xmx. A nemusi clovek vedet jak se ladi velky server. Zvlast pokud zadavatel pozaduje, aby aplikace vyuzila veskerou dostupnou pamet, kterou ji OS dovoli prideli. Davat do Xmx vysoka cisla nema moc smysl, kdyz je pameti mene, nez napisete, tak uvidite krasne uswapovanou Javu pri kazdem behu GC nad starou generaci, ktera odswapuje zbytek odswapovatelnych veci v OS... jenze nasledne si je OS zase priswapuje a odswapuje vam eden.
Co to bylo za aplikaci? Nejake zpracovani velkych fotografii...
hehe no jestli zacne byt i eden swapovan, tak to uz je aplikace prakticky v trapu, takze prave proto je dobre tyto volby znat a kdyztak si s nimi pohrat - nekdy nema cenu mit 100MB rozdelene tak, ze je eden porad vytezovany (GC se vola 50x za sekundu) a obrovsky old/tenured je naplnen jen z 5% - jen priklad.
Jestli jsem to dobre pochopil, tak se zde nepise o nejakem specialnim stylu programovani aplikace ale naopak o tom, jak se ma aplikace optimalne spoustet, coz vetsinou (?) neni vec vyvojaru ale adminu.
A v praxi se clovek dost casto setka s tim, ze dostane virtualni masinu pro svuj server a musi si vystacit napriklad jen s 64MB nebo 128MB pro system+JRE, takze nejake poladeni -Xms + pomer young/old se drive ci pozdeji bude muset stejne udelat.
Ahoj, mel bych prosbu. Pokud bude autor psat dalsi clanky o gc (a vsichni doufame ze bude ;)), mohl by se zamerit take na testovani paralelnich gc ? Nejde mi ani tak o teorii (prestoze i tu si rad prectu) spis bych chtel videt realne zapojeni vicejadernych procesoru pri gc. Vyzadovalo by to tedy stroj s aspon 4 jadry (skutecnymy). Opravdu by me zajimaly vysledky (tedy realne vysledky na artifical prikladech ;)), jak moc to pomohlo, kde to ma limity etc.
Zdravim, prave na parallel GC se zamerim priste ;-) Mam tady testovaci nasinu s osmi jadry a sam jsem zvedavy, jak se budou vysledky lisit - u SPECjbb ma paralelni GC doost velky vliv, ovsem kvuli licenci zatim tyto vysledky neni mozne zverejnit :-( takze budu muset nejaky vhodny test jest vymyslet.
U vice vlaken nemuze GC (bezici skryte taky ve svem vlakne, podobne jako casti GUI atd.) vlastne nic dopredu predikovat, takze heap nerozdeluje. Vlakna maji "pouze" svuj zasobnik resp. obecne sadu zasobnikovych ramcu (nemusi se jednat o kontinualni oblast pameti), ovsem zde jsou ulozeny pouze promenne primitivnich datovych typu a odkazy (reference) na objekty na halde - vse ostatni je sdilene per proces.
No dokud se ten objekt nestane přístupný jiným vláknům, tak by IMHO bylo výhodné mít oddělený heap a dokud tam není objekt s nahrazenou metodou finalize, bylo by možné po skončení vlákna tyto všechny objekty naráz odstranit. Nebo spíše ty, na které vidí jiné vlákno, zachovat (překopírovat někam jinam) a pak to celé odstranit.
Jinak k tomuto pohledu mě dovedla mj. tato část článku:
"Na tomto místě je vhodné poznamenat, že správce paměti většinou běží v samostatném vláknu a NEmusí zamykat všechny objekty, s nimiž pracuje, což znamená, že vlákno/vlákna aplikace ve skutečnosti nemusí být pozastavena na takovou dobu, jaká je uvedena ve výpisu."
Říkám si, pokud je teda ta oblast sdílená na proces, jak pak je možné některým vláknům umožnit běžet? (Smysl by dával právě ten úklid v rámci vlákna, který by neohrozil běh ostatních vláken.)
"ovsem zde jsou ulozeny pouze promenne primitivnich datovych typu a odkazy (reference) na objekty na halde"
Nevím, jak moc to je pokročilé (já JVM nevyvíjím), ale prý zde může být i celý objekt, u kterého je díky escape analysis jasné, že bude zrušen do konce běhu metody.
Souhlasím s tím, že je výhodné mít heap per vlákno, protože minimálně alokace v heapu, byť primitivní posunutí nějakého ukazatele se může stát úzkým hrdlem, pokud se hodně alokuje a dochází na heapu k častým kolizím.
Já ve svém programování zpravidla používám clustery, kdy se nejprve alokuje větší cluster a do něho se provádí alokace v rámci vlákna, nebo objektu, který něco potřebuje alokovat (u něhož se předpokládá, že buď poběží v jednom vláknu, nebo si sám ošetří sdílený přístup). Zatím jsem neprováděl žádné extra testy, ale tento způsob mi přijde jako lepší z hlediska MT, než používání globálního sdíleného heapu. Pravda, je trochu víc paměťově náročný, protože občas se stává, že cluster je větší, než je nakonec potřeba.
Mám to udělaný tak, že se zaalokuje další. Navíc mám tam víc typů alokátorů. Jeden co se používá na alokaci objektů stejné velikosti, to se hodí třeba na uzly stromu, nebo spojových seznamů, pak to má i tu výhodu, že jsou často ty uzly někde u sebe. Každý nový cluster je o jeden prvek větší, alokují se tedy 1,2,3,4,5 prvků (1,3,6,10,15 celkem). Přednostně se alokují uvolněná místa.
Druhý typ clusteru slouží pro objekty různých velikostí a alokují se inkrementálně, prostě každá další alokace posune konec minihaldy v clusteru o n bytů. Když se dojde na konec clusteru, zaalokuje se další. Když se dealokuje, pouze se odečte počet zaalokovaných bajtů, ale uvolněné díry se už nealokují. Jakmile počet alokovaných bajtů klesne na nulu, uvolní se celý cluster. Nevýhodou tohoto alokátoru je, že může být neefektivní, protože může nastat situace, kdy v clustery velikém 4KB zůstane objekt mající 4b a pak se celý cluster musí držet v paměti, nedá se jinak použít, protože jak bylo řečeno, uvolněná paměť v tomto clusteru se již nealokuje.
V obou případech mám alokaci v clusteru s jednotkovou složitostí, dealokace má složitos LOG N, kde N je počet clusterů. Oba clustery mají skoro nulouvou paměťovou režii na správu jednotlivých alokovaných bloků, zpravidla je to pár bajtů (8-16b) na celý cluster (který má kilobajty)
PS: Jasně, mám to v C++, ale šlo mi o to, aby se člověk na celý problém podíval víc zevrubně, než jen z pohledu "paměť neřeším, mám GC". Podle mě různé algoritmy mají různé nároky na způsoby alokace,
Ja tomu rozumim, ze v mnoha ohledech by byla moznost heap per thread zajimava a z hlediska naroku GC mozna i jednodussi.
Problem tvurci hotspotu pravdepodobne(?) videli v tom, ze v kodu muze byt neco na tento zpusob:
while (true) { if (random.nextBoolean()) { new myThread().run(); } }
no trosku prehanim :-) ale jde o to, ze o poctu vlaken je rozhodnuto az v runtime a ve chvili, kdy vlakno vznikne by musel GC nejak preorganizovat heap (defragmentace atd.) aby uvolnil dostatecnou (jak moc dostatecnou - treba pro vlakno co jen obslouzi jeden HTTP dotaz a potom umre staci 10k nebo radeji 1M?) kapacitu pro young generation.
V extremnim pripade by pak na heapu bylo alokovano n prazdnych oblasti young generation pro n vlaken, takze by bud jejich kapacita byla velmi mala (caste volani GC nebo casty zapis do tenured) nebo by se zabrala cast tenured.
Urcite by to slo resit, pravdepodobne nejakou analyzou v runtime, ale prozatim nevim, ze by to nejaky GC dokazal dobre osefovat :-(
Dalo by se to třeba řešit profilováním a to IMHO i celkem úspěšně. A i kdyby to bylo potřeba při vytvoření vlákna uvést ručně, byla by to IMHO celkem levná ruční optimalizace.
Jinak mě napadá, že by vlákno mohlo dostat svou vlastní oblast celkem malou (třeba jen eden) a pak použít sdílenou paměť.
K myšlence mě asi přivedla představa serveru s krátkými požadavky. Pokud by se to dobře poladilo, stop-the-world by zde mohlo téměř zmizet (využívalo by se hlavně na sessions).
Jinak pořád jsem nepochopil, jak je v současném stavu možné udělat stop-the-world jen pro vlákno.
článek je zajímavě napsaný, ale jednu věc trochu opominul (kromě více procesorů, které jsou slíbeny na příště):
Při jednotlivých nastaveních nejde jen o počet GC a jejich celkový čas za dobu běhu programu, ale taky čas trvání jednotlivých pauz. Kdyby měl program trochu (hodně) delší dobu života a heap měl nastaven na třeba 40g, tak by sice GC běžel málokrát, Full GC by běžel za dlouho, ale zato je schopný běžet i víc něž minutu, což už dokáže nadělat paseku.
Na této vlastnosti je zákeřné to, že jsou často testovací prostředí hůře hw vybavena (aby se výkonnostní problémy dříve objevily) a test běží chvíli, takže se tam problém neobjeví (když má třeba 8g, tak GC trvá místo prům. třeba 40s "jen" 8s).
Ještě jsem potkal takový hezký plugin dod JVisualVM:
http://redstack.wordpress.com/2011/01/06/visualising-garbage-collection-in-the-jvm/ (via http://twitter.com/#!/pjuza )
Já si nemůžu pomoct, ale může opravdu smajlík ukončit větu v závorce
...(samozřejmě vhodně zfalšovanou :-)... nemělo by to být spíš ...(samozřejmě vhodně zfalšovanou :-))... Takhle to moje čtecí zařízení interpretuje jako "samozřejmě vhodně zfalšovanou :-", a String ":-" ještě v internetové češtině myslím není :-).