Využití komprimovaných ukazatelů na objekty v JVM

16. 12. 2010
Doba čtení: 19 minut

Sdílet

V dnešní části seriálu o novinkách, které můžeme najít v syntaxi a sémantice programovacího jazyka Java i v jeho virtuálním stroji, si popíšeme vlastnost, která sice byla původně plánována až pro oficiální verzi JDK 7, ale nakonec ji mohou využít i programátoři a uživatelé používající JDK 1.6.0 14 a samozřejmě také OpenJDK 6. Jedná se o zavedení takzvaných komprimovaných ukazatelů na objekty, které lze používat na 64bitových platformách, včetně x86_64.

Úvodník

V dnešní části seriálu o novinkách, které můžeme najít v syntaxi a sémantice programovacího jazyka Java i v jeho virtuálním stroji, si popíšeme vlastnost, která sice byla původně plánována až pro oficiální verzi JDK 7, ale nakonec ji mohou využít i programátoři a uživatelé používající JDK 1.6.0 14 a samozřejmě také OpenJDK 6. Jedná se o zavedení takzvaných komprimovaných ukazatelů na objekty, které lze používat na 64bitových platformách, včetně x86_64.

Obsah

1. Využití komprimovaných ukazatelů na objekty v JVM

2. Platforma i386 a 32bitové operační systémy

3. Platforma x86_64 – rozšíření adresování na 64 bitů

4. JVM v 32bitových a 64bitových systémech

5. Komprimované ukazatele na objekty

6. Co se stane s hodnotami NULL?

7. Testovací příklady

8. Porovnání rychlosti a obsazení paměti při použití komprimovaných ukazatelů

9. Odkazy na Internetu

1. Využití komprimovaných ukazatelů na objekty v JVM

Ve všech předchozích pěti částech seriálu o novinkách, které lze najít v JDK 7, jsme se zabývali především těmi novými vlastnostmi platformy Javy, které jsou skutečně implementovány až v sedmé verzi JDK, popř. – alespoň prozatím – jako zcela samostatný projekt, který lze spolu s JDK 7 použít (jedná se především o projekt Lambda popsaný minule a předminule). Dnes si naopak popíšeme jednu vlastnost JDK, která sice byla původně plánována až pro JDK 7, ovšem vzhledem k tomu, že zavedení tohoto vylepšení nevedlo k nutnosti změny syntaxe ani sémantiky jazyka a dokonce ani nedošlo k žádným změnám v generovaném bajtkódu, se tato novinka mohla objevit již v novějších verzích OpenJDK 6 a taktéž v oficiálním (binárním) JDK 6 nabízeným firmou Oracle. Konkrétně je tato vlastnost zahrnuta v JDK 1.6.0_14 (6u14) (je o přibližně rok staré vydání JDK) a samozřejmě i ve všech následujících (novějších) oficiálních vydáních JDK 6.

Vlastnost JDK, kterou se dnes budeme zabývat, se jmenuje compressed oops, což je možné přeložit jako komprimované ukazatele na (obyčejné) objekty, neboť zkratka oop ve skutečnosti vznikla ze sousloví „ordinary object pointer“ a poslední „s“ ve zkratce je jen vyjádřením množného čísla v angličtině. Zkratkou oop jsou pojmenovány ukazatele na objekty vytvářené a spravované v rámci virtuálního stroje. Programátoři vytvářející programy v Javě vědí, že v jejich programech je možné používat jak primitivní datové typy (celá čísla, znaky, numerické hodnoty s pohyblivou řádovou čárkou, pravdivostní hodnotu), tak i objektové typy (referenční typy). Proměnné či atributy primitivních datových typů jsou reprezentovány přímo svou hodnotou, zatímco objektové typy jsou uloženy jako reference, což není nic jiného než ukazatel na objekt vytvořený na haldě – heapu (ve skutečnosti však specifikace JVM neříká, že se musí jednat o přímé ukazatele na instance javovských tříd, protože například pro rychlé přesuny objektů v rámci haldy mohou být vhodnější ukazatele nepřímé). V samotné Javě nejsou tyto ukazatele přímo měnitelné, ani s nimi nelze provádět ukazatelovou aritmetiku (tak jako je tomu v céčku či C++), ale jejich hodnotu je možné zjistit například v různých monitorovacích a debugovacích nástrojích.

2. Platforma i386 a 32bitové operační systémy

Maximální velikost haldy a tím pádem i počet objektů, které se na haldu mohou uložit, je shora omezena jak možnostmi operačního systému, tak i použitým mikroprocesorem a jím podporovaným rozsahem adres. Programovací jazyk Java byl i se svým běhovým prostředím (JRE) portován na počítače PC v dobách, kdy byly tyto počítače vybavené 32bitovými mikroprocesory (JDK 1.0 začalo být nabízeno v roce 1996, 32bitové mikroprocesory řady x86 existují již od roku 1985). Tyto mikroprocesory sice mohly být z důvodu zpětné kompatibility s aplikacemi určenými pro operační systém DOS přepnuty do šestnáctibitového režimu (buď se jednalo o reálný režim – real mode – či o režim virtuální), nicméně samotné běhové prostředí Javy (JRE) bylo určeno pro nativní plnohodnotný 32bitový režim těchto mikroprocesorů, v němž se používají 32bitové pracovní registry a 32bitové ukazatele. Kvůli použití 32bitových ukazatelů (včetně 32bitového PC a ESP) je možné adresovat a tím pádem i využít „pouze“ adresní prostor o velikosti 4 GB (232 bajtů), do něhož jsou však kromě vlastní operační paměti adresovány například i oblasti paměti dostupné přes PCI sběrnici či port AGP (typicky se jedná o framebuffer grafické karty) a část z tohoto rozsahu si nárokuje i samotné jádro operačního systému (v případě Linuxu až 1 GB adresního rozsahu).

Informace uvedené v předchozím odstavci jsou poněkud zjednodušené, protože šířka logické adresy může díky použití selektorů dosáhnout až 13+1+32=46 bitů (zmíněných 13+1 bitů je umístěno v příslušném 16bitovém selektoru, který nahradil původní segmentové registry známé z reálného režimu, přičemž 13 bitů ukazuje do globální či lokální tabulky deskriptorů a zbývající bit rozhoduje o tom, zda se použije lokální či globální tabulka deskriptorů – LDT či GDT). Ovšem výsledná fyzická adresa je na původní architektuře x86 skutečně jen 32bitová, a to bez ohledu na to, zda je zapnuto či vypnuto stránkování (paging). Navíc se v současných operačních systémech používá pouze stránkování a použití selektorů/des­kriptorů se obchází takovým způsobem, že se rozsahy všech čtyř selektorových segmentů nastavují na plný rozsah 4 GB a nulovou bázovou adresu. Částečně lze zmíněné omezení adresového prostoru na rozsah „pouhých“ čtyř gigabajtů na moderních mikroprocesorech (a systémech, které to umožňují!) obejít použitím PAE (Physical Address Extension) a zvýšit tak adresovatelnou kapacitu operační paměti v Linuxu až na 64 GB. Větší adresní rozsah je při použití PAE zajištěn díky použití 64bitových adres v tabulce stránek – page table. Ovšem velikost ukazatelů používaných jednotlivými procesy zůstává stále omezena na 32 bitů. Z toho vyplývá, že jeden proces (například již zmíněné běhové prostředí Javy – JRE i se svou haldou) může stále využívat maximálně necelé čtyři gigabajty operační paměti.

3. Platforma x86_64 – rozšíření adresování na 64 bitů

Java však samozřejmě není používána pouze na 32bitových platformách. Některé moderní mikroprocesory používané na PC je totiž možné přepnout, pokud k tomu samozřejmě existuje podpora v operačním systému, do plnohodnotného 64bitového režimu označovaného jako x86_64 (různí výrobci procesorů používají různá označení, zmíněné x86_64 je neutrální a nepreferuje registrované názvy jednotlivých výrobců CPU). V tomto režimu se bitová šířka pracovních registrů (používaných kromě běžných aritmetických a logických operací mj. i pro adresování) zvyšuje na plných šedesát čtyři bitů a navíc se namísto původní osmice pracovních 32bitových registrů EAX, EBX, ECX, EDX, EBP, ESP, ESI, EDI používá dvojnásobný počet pracovních registrů RAX, RBX, RCX, RDX, RBP, RSP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15, čehož samozřejmě využívá jak interpret Javy, tak i JIT překladač, jehož úkolem je detekovat ty části javovského kódu, které se často používají a tyto bloky následně přeložit do nativního kódu mikroprocesoru. Díky použití 64bitových ukazatelů je teoreticky možné i v rámci jednoho procesu adresovat až 16 EB paměti (264 bajtů), i když v současnosti je z praktických důvodů tato kapacita omezena na 40 až 48 bitů adresy, což odpovídá 240=1 TB až 248=256 TB.

Například u mikroprocesorů Opteron lze použít 48 bitů virtuální adresy a 40 bitů fyzické adresy, což jinými slovy znamená, že nelze nainstalovat více než 1 TB operační paměti. To je minimálně pro osobní počítače prozatím skoro neskutečná kapacita, i když, kdo ví, kam se v budoucnu posunou nároky neustále vznikajícího bloatware :-). Větší rozsah fyzické adresy, konkrétně 48 bitů, podporují například mikroprocesory Intel Core i3, Intel Core i5, Intel Core i7, Intel Atom a taktéž AMD Phenom. V současných verzích mikroprocesorů jsou dokonce i tabulky paměťových stránek zmenšeny (optimalizovány) takovým způsobem, že se v nich používají pouze 48 bitové adresy s tím, že se předpokládá, že čtyřicátý osmý bit adresy (s indexem 47) je při výpočtech adres zdánlivě opakován i ve zbývajících vyšších bitech s indexy 48 až 63 (jakoby byla adresa celým číslem se znaménkem). Ve výsledku se tedy celý 64bitový adresní rozsah mikroprocesoru rozdělí na tři části – spodní oblast paměti (adresy 00000000 0000­0000 až 00007FFF FFFFFFFF), kde jsou uloženy aplikace a jejich data, neobsazenou oblast o rozsahu 00008000 0000­0000 až FFFF7FFF FFFFFFFF a konečně o horní oblast paměti o rozsahu FFFF8000 0000­0000 až FFFFFFFF FFFFFFFF rezervovanou pro potřeby jádra – viz též vysvětlující obrázky na Wikipedii http://en.wiki­pedia.org/wiki/X86–64#Canonical_for­m_addresses.

4. JVM v 32bitových a 64bitových systémech

Aplikace naprogramované v Javě jsou, jak je známo, do velké míry nezávislé na použité platformě i operačním systému. Mezi výjimky v nezávislosti patří například volání nativních funkcí nebo různé chyby (které kupodivu nebývají kompatibilní mezi jednotlivými systémy :-). Ovšem vlastnosti platformy i operačního systému přesto chování javovských programů ovlivňují. Týká se to především maximální velikosti haldy, která může mít na 32bitových platformách maximální teoretickou velikost 4 GB (prakticky je to cca 2,5 GB), protože se pro adresování objektů na haldě uložených používají nativní 32bitové ukazatele. Naproti tomu při přechodu na 64bitovou platformu používá JVM interně 64bitové nativní ukazatele a velikost haldy je tudíž na současných počítačích prakticky neomezená. Mohlo by se tedy zdát, že programátoři ani uživatelé používající javovské programy na 64bitových platformách (dnes především na platformě x86_64) nebudou mít díky větší maximální velikosti haldy s provozem i rozsáhlých a datově náročnějších aplikací žádné problémy, spíše naopak.

Ve skutečnosti ovšem použití nativních 64bitových ukazatelů může mít v některých případech negativní dopad na výkonnost aplikací a také na potřebnou kapacitu operační paměti, kterou je zapotřebí alokovat pro haldu (heap). Samotná operační paměť je sice dnes poměrně levnou komoditou, to ovšem ani zdaleka neplatí pro vyrovnávací paměti první a druhé úrovně, jejichž velikost a rychlost do značné míry ovlivňuje výkonnost celého počítače. To znamená, že pokud je například kvůli použití 64bitových ukazatelů nutné alokovat cca 1,5 násobek velikosti haldy potřebné původně v 32 bitovém prostředí, bude při přístupu k objektům docházet častěji k výpadkům stránek z vyrovnávací paměti a celý výpočet se zpomalí (množství přístupů k objektům na haldě navíc není možné snadno ovlivnit, protože ve vláknech na pozadí běží garbage collector, což bude mimochodem téma některého z dalších článků). Vývojáři JDK ve firmě Oracle provedli měření, o kolik se zvýší potřebná kapacita haldy při přechodu z 32bitových na 64bitové ukazatele a došli k hodnotám 20% až 50% – to znamená, že některé programy používají velké množství referencí, které významným způsobem ovlivňují zaplnění haldy (viz též hodnoty uvedené v osmé kapitole).

5. Komprimované ukazatele na objekty

Zdánlivě jsme se tedy ocitli v určité pasti: použití platformy x86_64 je sice z jednoho pohledu velmi výhodné, protože je možné používat dvojnásobný počet pracovních registrů a kapacita haldy je prakticky neomezená, ovšem na druhou stranu je na haldě nutné alokovat o x-desítek procent více bajtů, což vede k větší pravděpodobnosti výpadků stránek z vyrovnávací paměti a tudíž i ke zpomalení výpočtů. Nicméně právě v tomto ohledu je možné využít toho, že javovské programy nejsou překládány přímo do nativního kódu, ale jsou buď interpretovány v JRE popř. až v době běhu aplikace překládány JITem. Navíc programátoři nemají v Javě možnost přímo pracovat s hodnotami referencí na objekty – mohou tyto reference pouze vytvářet (operátorem new či konstrukcí statického pole), předávat jako parametry a přiřazovat je atributům a lokálním proměnným. Z tohoto důvodu je možné – na rozdíl od například céčkovských programů – aby se namísto nativních 64bitových ukazatelů (=referencí na objekty) používaly například pouze 32bitové ukazatele.

Výsledkem této myšlenky jsou komprimované ukazatele neboli compressed oops. Tyto ukazatele mají i na platformě x86_64 šířku 32bitů, ovšem neobsahují přímo adresu objektu na haldě, nýbrž index vyjádřený jako násobek osmi bajtů. Jinými slovy – skutečná adresa objektu na haldě se vypočítá z 32bitového indexu vynásobeného osmi, neboli posunutého o tři bity doleva (jiné hodnoty posunu a tím pádem i jinou maximální velikost haldy, prozatím nejde nastavit). To znamená, že všechny objekty musí být na haldě zarovnané na osm bajtů, což v reálných případech není nijak velké plýtvání pamětí. Díky 32bitovým indexům lze mít na haldě uloženy až 4 miliardy objektů (přesněji 232-1) a současně může velikost haldy dosahovat velikosti až 32 GB (232×8). Pokud je při spuštění JRE specifikováno (-Xmx atd.), že má mít halda větší kapacitu než 32 GB, je použití komprimovaných ukazatelů automaticky vypnuto (s takovou aplikací jsem se sice prozatím nesetkal, ale věřím, že například pro nějaké in-memory databáze existuje). V některých verzích JDK nejsou i při menší kapacitě haldy komprimované ukazatele povoleny, což je možné při startu JRE napravit následujícím přepínačem:

-XX:+UseCompressedOops

Někdy je výhodné naopak použití compressed oops zakázat, protože některé nástroje (debuggery) mohou mít problémy s analýzou obsahu haldy (navíc byla teprve nedávno opravena chyba, která způsobovala pády Eclipse):

-XX:-UseCompressedOops

Navíc se použití komprimovaných ukazatelů týká pouze běžícího programu, protože v překládaném bajtkódu k žádným změnám nedošlo (ostatně v samotném bajtkódu existuje množství zcela jiných omezení týkajících se počtu atributů a konstant v jedné třídě, počtu metod, délky metod, počtu parametrů metod, počtu lokálních proměnných a počtu dimenzí pole).

6. Co se stane s hodnotami NULL?

S komprimovanými ukazateli souvisí ještě jeden problém, který se týká způsobu práce s hodnotou NULL. Tato hodnota bývá interně skutečně reprezentována nulou (tj. ukazatelem na adresu 0), ovšem vzhledem k tomu, že se explicitní či implicitní test na NULL vyskytuje v běžících programech velmi často (častěji jde o test implicitní prováděný například při volání metod), je v JRE použita velmi jednoduchá a většinou i účinná metoda, která nutnost provádění těchto testů eliminuje. Halda je jak na 32bitových, tak i na 64bitových platformách umístěna v segmentu paměti s nulovou bázovou adresou a navíc nultá stránka paměti buď není vůbec mapována nebo je do ní zakázán přístup (samotná halda však nemusí ve skutečnosti začínat již od počátku paměti, záleží na konkrétních hodnotách ukazatelů přidělovaných JRE). To znamená, že pokud se programátor bude snažit přistupovat k objektu přes referenci rovnou NULL (adresa=0), dojde na úrovni operačního systému k poslání signálu do JRE, která tento signál většinou zpracuje jednoduše tak, že v aplikaci vyvolá nechvalně známou výjimku NPE – Null Pointer Exception (samotný systém žádný test na přístup k nulté stránce samozřejmě neprovádí, to je věcí mikroprocesoru a v něm integrovaného řadiče paměti).

Daní za toto zjednodušení a urychlení práce JRE je však to, že celá jedna stránka paměti (běžně 4 kB, pokud se nepoužívají huge-pages) není využitelná pro žádná data. Při použití komprimovaných ukazatelů se JRE taktéž snaží o vytvoření haldy v paměti s nulovou bází a opět se snaží o uzamknutí nulté stránky paměti. Po dekódování adresy z indexu, tj. po bitovém posuvu indexu o tři bity doleva, je většinou provedeno zdánlivé čtení z dekódované adresy, které v případě, že se jedná o referenci NULL opět vede k vyvolání výjimky mechanismem podobným, jaký byl popsán výše. U těch platforem, kde není možné, aby halda začínala od adresy 0, se alespoň na úrovni JRE eliminují testy na NULL u těch typů referencí, u nichž je zřejmé, že tuto speciální hodnotu nikdy nebudou obsahovat. Týká se to například návratové hodnoty metody Object.getClas­s().

7. Testovací příklady

Pro účely testování vlivu použití komprimovaných ukazatelů na celkové využití haldy můžeme použít demonstrační příklady, jejichž paměťové nároky lze prozkoumat například nástrojem jconsole, který se dokáže připojit k běžící JRE a zjistit velké množství parametrů tohoto virtuálního stroje. Může se přitom jednat jak o virtuální stroj běžící na stejném počítači jako samotná jconsole, tak i o vzdálené JRE, což je zvláště výhodné například pro monitorování zatížení serverů. První demonstrační příklad je velmi jednoduchý – po svém spuštění vytvoří seznam, do něhož vloží n objektů typu Pair, z nichž každý obsahuje dvojici objektů typu Item. Na haldě by se po zkonstruování n objektů a jejich vložení do seznamu měla alokovat paměť obsahující jak hodnoty primitivního datového typu int (což jsou 4 bajty), tak i množství referencí, které mohou mít podle nastavených parametrů JRE i možností použité platformy délku čtyř nebo osmi bajtů. Zdrojový kód tohoto příkladu je velmi jednoduchý:

import java.util.*;
 
class Item
{
    public Item(int i)
    {
        this.i = i;
    }
    int i;
}
 
class Pair
{
    public Item item1;
    public Item item2;
 
    public Pair(int i1, int i2)
    {
        this.item1=new Item(i1);
        this.item2=new Item(i2);
    }
}
 
public class Test
{
    public static void main(String[] args)
    {
        System.console().readLine("press enter to begin");
 
        int n = Integer.parseInt(args[0]);
        List<Pair> list = new ArrayList<Pair>();
        for (int i=0; i<n; i++)
        {
            if (i%1000 == 0)
            {
                System.out.print(i + "\t");
            }
            list.add(new Pair(i, i));
        }
 
        System.console().readLine("\ndone, press enter again");
    }
}

Druhý demonstrační příklad byl získán ze stránky Great Computer Language Shootout (http://c2.com/cgi/wi­ki?GreatCompu­terLanguageSho­otout). V tomto příkladu se vytváří binární strom, jehož uzly obsahují jak reference na dvojici poduzlů, tak i uloženou hodnotu typu int. I v tomto případě by měl být rozdíl mezi použitím komprimovaných ukazatelů a nekomprimovaných ukazatelů na platformě x86_64 při měření viditelný:

/* The Great Computer Language Shootout
   http://shootout.alioth.debian.org/
  
   contributed by Jarkko Miettinen
*/
 
public class binarytrees {
 
    private final static int minDepth = 4;
 
    public static void main(String[] args){
        int n = 0;
        if (args.length > 0) n = Integer.parseInt(args[0]);
 
        int maxDepth = (minDepth + 2 > n) ? minDepth + 2 : n;
        int stretchDepth = maxDepth + 1;
 
        int check = (TreeNode.bottomUpTree(0,stretchDepth)).itemCheck();
        System.out.println("stretch tree of depth "+stretchDepth+"\t check: " + check);
 
        TreeNode longLivedTree = TreeNode.bottomUpTree(0,maxDepth);
 
        for (int depth=minDepth; depth<=maxDepth; depth+=2){
            int iterations = 1 << (maxDepth - depth + minDepth);
            check = 0;
 
            for (int i=1; i<=iterations; i++){
                check += (TreeNode.bottomUpTree(i,depth)).itemCheck();
                check += (TreeNode.bottomUpTree(-i,depth)).itemCheck();
            }
            System.out.println((iterations*2) + "\t trees of depth " + depth + "\t check: " + check);
        }
        System.out.println("long lived tree of depth " + maxDepth + "\t check: "+ longLivedTree.itemCheck());
    }
 
    private static class TreeNode
    {
        private TreeNode left, right;
        private int item;
 
        TreeNode(int item){
            this.item = item;
        }
 
        private static TreeNode bottomUpTree(int item, int depth){
            if (depth>0){
                return new TreeNode(
                        bottomUpTree(2*item-1, depth-1)
                        , bottomUpTree(2*item, depth-1)
                        , item
                );
            }
            else {
                return new TreeNode(item);
            }
        }
 
        TreeNode(TreeNode left, TreeNode right, int item){
            this.left = left;
            this.right = right;
            this.item = item;
        }
 
        private int itemCheck(){
            // if necessary deallocate here
            if (left==null) return item;
            else return item + left.itemCheck() - right.itemCheck();
        }
    }
}

8. Porovnání rychlosti a obsazení paměti při použití komprimovaných ukazatelů

V materiálech firmy Oracle se píše o tom, že se použitím komprimovaných ukazatelů může výrazně snížit velikost haldy a současně i urychlit běh aplikací. To je sice z teoretického hlediska oprávněné tvrzení, protože jediná operace navíc, kterou musí JITovaný kód s komprimovanými ukazateli provést, jsou bitové posuny, ovšem statistické výsledky si samozřejmě musíme zfalšovat sami :-). Nejprve se podívejme, jak vypadá první příklad spuštěný na systému RHEL 5 na platformě x86_64. Testování probíhalo s IcedTea6 HEAD (zkompilováno dnes se standardními volbami při překladu), pro vlastní měření byl použit již zmíněný nástroj jconsole. U grafů si povšimněte i změřeného času běhu garbage collectoru. Ve všech případech byla maximální velikost haldy nastavena na 2,5 GB:

Graf 1: První demonstrační příklad při vložení 10 milionů prvků do seznamu se zapnutou komprimací ukazatelů.

Graf 2: První demonstrační příklad při vložení 10 milionů prvků do seznamu s vypnutou komprimací ukazatelů.

Graf 3: První demonstrační příklad při vložení 20 milionů prvků do seznamu se zapnutou komprimací ukazatelů.

Graf 4: První demonstrační příklad při vložení 20 milionů prvků do seznamu s vypnutou komprimací ukazatelů.

Druhý demonstrační příklad byl spuštěn s volbou 23, která určuje maximální hloubku vytvářeného stromu (24 úrovní). U tohoto příkladu jsem změřil i čas běhu programu pomocí unixové utility time. Čas tedy zahrnuje i spuštění JRE a prvotní „JITování“ bajtkódu do nativního strojového kódu:

Druhý demonstrační příklad spuštěný se zapnutou komprimací ukazatelů:

real    1m23.141s
user    2m23.154s
sys     0m1.465s

Druhý demonstrační příklad spuštěný s vypnutou komprimací ukazatelů:

real    3m48.769s
user    6m9.920s
sys     0m2.323s

Rozdíly v časech běhu jsou mj. způsobeny i rozdílnou dobou běhu garbage collectoru, což je ostatně patrné i z údajů uvedených pod následujícími gra­fy:

Graf 5: Druhý demonstrační příklad při hloubce binárního stromu 24 úrovní se zapnutou komprimací ukazatelů.

bitcoin_skoleni

Graf 6: Druhý demonstrační příklad při hloubce binárního stromu 24 úrovní s vypnutou komprimací ukazatelů.

Výše uvedené grafy a hodnoty skutečně ukazují snížení alokované paměti pro haldu, ovšem měření pro konkrétní situaci (například aplikační server s nasazenými aplikacemi) si samozřejmě musí vývojář provést sám – je totiž pravděpodobné, že jím naměřené hodnoty se mohou odlišovat.

9. Odkazy na Internetu

  1. Compressed oops in the Hotspot JVM
    http://wikis.sun­.com/display/Hot­SpotInternals/Com­pressedOops
  2. 32-bit or 64-bit JVM? How about a Hybrid?
    http://blog.ju­ma.me.uk/2008/10/­14/32-bit-or-64-bit-jvm-how-about-a-hybrid/
  3. Compressed object pointers in Hotspot VM
    http://blogs.sun­.com/nike/entry/com­pressed_objec­t_pointers_in_hot­spot
  4. Java HotSpot™ Virtual Machine Performance Enhancements
    http://downlo­ad.oracle.com/ja­vase/7/docs/techno­tes/guides/vm/per­formance-enhancements-7.html
  5. Using jconsole
    http://downlo­ad.oracle.com/ja­vase/1.5.0/doc­s/guide/manage­ment/jconsole­.html
  6. jconsole – Java Monitoring and Management Console
    http://downlo­ad.oracle.com/ja­vase/1.5.0/doc­s/tooldocs/sha­re/jconsole.html
  7. Great Computer Language Shootout
    http://c2.com/cgi/wi­ki?GreatCompu­terLanguageSho­otout
  8. x86–64
    http://en.wiki­pedia.org/wiki/X86–64
  9. Physical Address Extension
    http://en.wiki­pedia.org/wiki/Phy­sical_Address_Ex­tension
  10. Java performance
    http://en.wiki­pedia.org/wiki/Ja­va_performance
  11. 1.6.0_14 (6u14)
    http://www.ora­cle.com/technet­work/java/java­se/6u14–137039.html?ssSou­rceSiteId=otncn
  12. Update Release Notes
    http://www.ora­cle.com/technet­work/java/java­se/releasenotes-136954.html
  13. 4.10 Limitations of the Java Virtual Machine
    http://java.sun­.com/docs/book­s/jvms/second_e­dition/html/Clas­sFile.doc.html#88659
  14. Java™ Platform, Standard Edition 7 Binary Snapshot Releases
    http://dlc.sun­.com.edgesuite­.net/jdk7/bina­ries/index.html
  15. Trying the prototype
    http://mail.o­penjdk.java.net/pi­permail/lambda-dev/2010-August/002179.html
  16. Better closures (for Java)
    http://blogs.sun­.com/jrose/en­try/better_clo­sures
  17. Lambdas in Java: An In-Depth Analysis
    http://www.in­foq.com/articles/lam­bdas-java-analysis
  18. Class ReflectiveOpe­rationExcepti­on
    http://downlo­ad.java.net/jdk7/doc­s/api/java/lan­g/ReflectiveO­perationExcep­tion.html
  19. Proposal: Indexing access syntax for Lists and Maps
    http://mail.o­penjdk.java.net/pi­permail/coin-dev/2009-March/001108.html
  20. Proposal: Elvis and Other Null-Safe Operators
    http://mail.o­penjdk.java.net/pi­permail/coin-dev/2009-March/000047.html
  21. Java 7 : Oracle pushes a first version of closures
    http://www.bap­tiste-wicht.com/2010/05­/oracle-pushes-a-first-version-of-closures/
  22. Groovy: An agile dynamic language for the Java Platform
    http://groovy­.codehaus.org/O­perators
  23. Better Strategies for Null Handling in Java
    http://www.sli­deshare.net/Step­han.Schmidt/bet­ter-strategies-for-null-handling-in-java
  24. Control Flow in the Java Virtual Machine
    http://www.ar­tima.com/under­thehood/flowP­.html
  25. Java Virtual Machine
    http://en.wiki­pedia.org/wiki/Ja­va_virtual_machi­ne
  26. ==, .equals(), compareTo(), and compare()
    http://leepoin­t.net/notes-java/data/expres­sions/22compa­reobjects.html
  27. New JDK7 features
    http://openjdk­.java.net/pro­jects/jdk7/fe­atures/
  28. Project Coin: Bringing it to a Close(able)
    http://blogs.sun­.com/darcy/en­try/project_co­in_bring_close
  29. ClosableFinder source code
    http://blogs.sun­.com/darcy/re­source/Projec­tCoin/Closeable­Finder.java
  30. Joe Darcy blog about JDK
    http://blogs.sun­.com/darcy
  31. Java 7 – more dynamics
    http://www.bap­tiste-wicht.com/2010/04­/java-7-more-dynamics/
  32. ArrayList (JDK 1.4)
    http://downlo­ad.oracle.com/ja­vase/1.4.2/doc­s/api/java/util/A­rrayList.html

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.