Vlákno názorů k článku Monitorování procesů a správa paměti v JDK 6 a JDK 7 (4) od Vít Šesták (v6ak) - Minule jsme zde nakousli situaci ve vícevláknovém prostředí....

  • Článek je starý, nové názory již nelze přidávat.
  • 18. 2. 2011 10:46

    Vít Šesták (v6ak)

    Minule jsme zde nakousli situaci ve vícevláknovém prostředí. A článek se o tom vlastně taky zmínil. Chtěl bych se zeptat, jak to tam vlastně vypadá. Každé vlákno si vytvoří svoji mladou generaci? Nebo si ukousne kousek z globální mladé generace? Jak je to s objekty sdílenými mezi vlákny?

  • 21. 2. 2011 10:38

    Pavel Tišnovský
    Zlatý podporovatel

    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.

  • 21. 2. 2011 11:06

    Vít Šesták (v6ak)

    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.

  • 21. 2. 2011 11:48

    ondra.novacisko.cz (neregistrovaný)

    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.

  • 21. 2. 2011 15:52

    Pavel Tišnovský
    Zlatý podporovatel

    Ten cluster se muze za behu zvetsovat/zmensovat nebo se pri jeho zaplneni proste naalokuje dalsi cluster? Uvolneni celeho clusteru je asi reseno klasicky pocitanim objektu v nem ze (to me prijde nejjednodussi).

  • 21. 2. 2011 21:40

    ondra.novacisko.cz (neregistrovaný)

    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,

  • 21. 2. 2011 15:49

    Pavel Tišnovský
    Zlatý podporovatel

    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 :-(

  • 21. 2. 2011 19:36

    Vít Šesták (v6ak)

    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.