Obsah
1. Pohled pod kapotu JVM – využití knihovny SDLJava v graficky náročných aplikacích
2. Základní vlastnosti knihovny SDLJava
4. První demonstrační příklad – nastavení celoobrazovkového grafického režimu
5. Překlad a spuštění prvního demonstračního příkladu
6. Druhý demonstrační příklad – vykreslení obdélníku
7. Třetí demonstrační příklad – double buffering
8. Repositář se zdrojovými kódy všech tří dnešních demonstračních příkladů
1. Pohled pod kapotu JVM – využití knihovny SDLJava v graficky náročných aplikacích
V předchozích částech seriálu o programovacím jazyku Java i o virtuálním stroji Javy jsme si popsali základní způsoby využití knihoven AWT, Swing a Java2D při tvorbě aplikací, na něž jsou kladeny velké požadavky na rychlost a/nebo plynulost vykreslování. Popsali jsme si i možné způsoby využití exkluzivních celoobrazovkových režimů, double bufferingu (implicitního double bufferingu v případě použití komponent knihovny Swing i explicitního double bufferingu při použití komponent AWT) či způsobů použití bitmap typu VolatileImage, které jsou uložené v paměti grafického akcelerátoru. Ovšem i přes poměrně velké možnosti, které nám knihovny AWT, Swing i Java2D nabízí nemusí být v některých případech výkon aplikace dostačující, a to většinou z toho důvodu, že mezi programovým kódem napsaným uživatelem v Javě a vlastním vykonáním nějaké grafické operace leží hned několik vrstev (další problém může nastat v případě aplikací s 3D grafikou, to je však již téma, kterému se budeme věnovat někdy příště).
U některých typů aplikací může být výhodnější se použití javovských knihoven AWT/Swing/Java2D zcela vyhnout a použít namísto nich nějakou nativní knihovnu, která bude požadované grafické operace nabízet. V případě 3D grafiky je tak možné využít OpenGL či Direct3D, ovšem pokud se jedná o 2D grafiku, nabízí se celkem zajímavá volba – využití nativní knihovny SDL, která je sama o sobě pouze relativně tenkou vrstvou mezi uživatelskými programy a multimediálními zařízeními (grafickou a zvukovou kartou, ale též klávesnicí, joysticky a myší či časovačem). Mezi přednosti SDL patří její jednoduchost (z toho se odvíjí i existence vazby mezi SDL a programovacími jazyky, i když její základní API je čistě céčkové), přenositelnost na různé platformy (včetně Androidu, minimálně v případě SDL 1.x) a v neposlední řadě taktéž existence několika doplňujících modulů, například modulu pro vykreslování TTF fontů, vytvoření grafického kontextu pro OpenGL, modulu pro komunikaci po síti atd. I díky těmto vlastnostem je SDL používána v mnoha úspěšných hrách, viz též http://en.wikipedia.org/wiki/List_of_games_using_SDL.
2. Základní vlastnosti knihovny SDLJava
V předchozí kapitole jsem se zmínil o tom, že API knihovny SDL je vytvořeno pro programovací jazyk C (což je současně i jazyk, v němž je tato knihovna implementována), ale existují i vazby pro další programovací jazyky. V případě Javy má programátor dvě možnosti. Buď si může vazbu na SDL vytvořit sám, například s přímým využitím JNI, popř. nemusí znovu vymýšlet kolo, ale namísto toho využít již existující knihovnu SDLJava. Tato knihovna nabízí propojení mezi Javou a SDL, přičemž Javovské API této knihovny je navrženo takovým způsobem, že je jeho použití pro programátora píšícího v Javě velmi přirozené a jednoduché (v některých ohledech jednodušší, než programové rozhraní vlastní knihovny SDL). SDLJava v současnosti podporuje SDL verze 1.2.x, což je prozatím nejrozšířenější verze SDL, i když relativně nedávno, konkrétně 13. 8. 2013 byla vydána SDL 2.0, která má odlišné API a nabízí odlišné funkce, které se více přibližují možnostem současných grafických akcelerátorů.
Využití SDLJava pro volání funkcí SDL z Javy má své přednosti, ale samozřejmě i zápory. Předností je v mnoha případech vyšší grafický výkon a taktéž (což může být možná poněkud překvapivé) i přenositelnost aplikace i na ty platformy, kde není oficiálně podporována Java SE (příkladem je systém Android). Jednou z nevýhod je nutnost zajistit při spuštění aplikace správnou funkci SDLJava, což především znamená, že JVM musí v čase běhu nalézt nativní knihovnu libsdljava.so či SDLJava.dll a současně musí být v systému nainstalována i knihovna SDL. Jedná se o stejný problém, se kterým se setká prakticky jakýkoli programátor, který část své aplikace vyvine ve formě nativní knihovny, jejíž funkce pak přes rozhraní JNI volá z Javovské části aplikace. Touto problematikou se budeme podrobněji zabývat v navazující kapitole.
3. Instalace knihovny SDLJava
V mnoha distribucích lze knihovnu SDLJava nalézt v repositářích dané distribuce, takže v tomto případě je instalace této knihovny velmi snadná (yum install, apt-get atd.). Pokud tento balíček v repositářích své distribuce nenaleznete popř. pokud chcete použít prozatím nejnovější verzi této knihovny, je možné velmi jednoduše provést „lokální instalaci“ do předem zvoleného adresáře, ovšem s tím omezením, že nativní část je přeložena pro 32bitovou platformu x86_64 (jinými slovy – nejlepší je stejně využít balíček z distribuce :-):
#!/bin/sh SDL_JAVA_VERSION=sdljava-0.9.1-linux-2.6-bin.tar.gz wget http://sourceforge.net/projects/sdljava/files/sdljava/0.9.1/$SDL_JAVA_VERSION/download -o $SDL_JAVA_VERSION tar xvfz $SDL_JAVA_VERSION
Na uvedené adrese http://sourceforge.net/projects/sdljava/files/sdljava/0.9.1/ je možné najít i knihovnu SDLJava pro Windows.
Nezávisle na tom, jakým způsobem se instalace provede, získáme minimálně dva důležité soubory – Javovskou část knihovny SDLJava, která je uložena v souboru nazvaném sdljava.jar a nativní část knihovny uloženou v souboru s názvem libsdljava.so popř. na systému Windows pod názvem SDLJava.dll. Archiv sdljava.jar je použit jak při kompilaci, tak i při běhu aplikací, tj. musí být umístěn na CLASSPATH, nativní knihovna libsdljava.so/SDLJava.dll je využita při běhu a většinou se na cestu k ní odkazujeme pomocí přepínače -Djava.library.path=cesta.
4. První demonstrační příklad – nastavení celoobrazovkového grafického režimu
Vlastnosti a možnosti nabízené knihovnou SDLJava si nejlépe ukážeme na demonstračních příkladech. Všechny dnes uvedené demonstrační příklady budou velmi jednoduché a současně budou využívat jen základní grafické možnosti knihovny SDLJava, zatímco dalšími možnostmi (zvuky, čtení stavů klávesnice a myši atd.) se budeme zabývat v navazujících částech tohoto seriálu. První demonstrační příklad uvedený v této kapitole je velmi jednoduchý a využívá pouze dvě třídy – sdljava.SDLMain a sdljava.video.SDLVideo.
Nejprve je provedena inicializace knihovny SDL s využitím statické metody SDLMain.init(), které se pomocí konstanty SDLMain.SDL_INIT_VIDEO předá informace o tom, že se bude využívat pouze grafický subsystém SDL. Následně je s využitím taktéž statické metody SDLVideo.setVideoMode() provedeno přepnutí do celoobrazovkového grafického režimu s rozlišením 800×600 pixelů a s bitovou hloubkou 16 bitů na pixel. Po uplynutí pěti sekund se aplikace korektně ukončí zavoláním metody SDLMain.quit() (ta je navíc zavolána i při vzniku jakékoli výjimky, aby se zamezilo tomu, že by aplikace po svém pádu neobnovila původní grafický režim).
Výpis zdrojového kódu prvního demonstračního příkladu:
import sdljava.SDLMain; import sdljava.video.SDLVideo; /** * Prvni demonstracni priklad vyuzivajici knihovnu sdljava. * Po spusteni se provede prepnuti do grafickeho rezimu 800x600x16 * a po peti sekundach se program ukonci. */ public class SDLTest1 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_WIDTH = 800; /** * Vertikalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_HEIGHT = 600; /** * Bitova hloubka vybraneho grafickeho rezimu. */ private static final int GFX_BPP = 16; /** * Spusteni demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL. SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace celoobrazovkoveho grafickeho rezimu SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, SDLVideo.SDL_FULLSCREEN); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim SDLMain.quit(); } } }
5. Překlad a spuštění prvního demonstračního příkladu
Podívejme se nyní na to, jakým způsobem se první demonstrační příklad přeloží a spustí. Překlad se provádí stejným postupem, jako překlad „obyčejných“ javovských aplikací, pouze je nutné správně nastavit cestu k Java archivu sdljava.jar. Pokud je tento archiv umístěn v podadresáři ./sdljava-0.9.1/lib, je překlad snadný a zajistí ho následující skript:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib javac -cp $SDL_JAVA_LIBS/sdljava.jar SDLTest1.java
V případě, že je knihovna SDLJava nainstalována v systému, je možné překlad provést následujícím způsobem:
#!/bin/sh javac -cp .:/usr/share/java/sdljava.jar SDLTest1.java
Spuštění aplikace je již nepatrně složitější, neboť je nutné správně nastavit cestu k nativní části knihovny SDLJava. Nejprve si ukažme první možnost – nativní část SDLJava (soubor libsdljava.so) je ve umístěna v podadresáři ./sdljava-0.9.1/lib:
#!/bin/sh SDL_JAVA_LIBS=./sdljava-0.9.1/lib java -cp .:$SDL_JAVA_LIBS/sdljava.jar -Djava.library.path=$SDL_JAVA_LIBS SDLTest1
Pokud je SDLJava součástí instalace systému, lze pro spuštění prvního demonstračního příkladu využít například následující skript:
#!/bin/sh java -cp .:/usr/share/java/sdljava.jar -Djava.library.path=/usr/lib64/sdljava SDLTest1
6. Druhý demonstrační příklad – vykreslení obdélníku
Ve druhém demonstračním příkladu se seznámíme se způsobem vykreslování. Samotná základní varianta knihovny SDL (a tím pádem i SDLJava) podporuje pouze dva vykreslovací příkazy. První příkaz, který slouží pro vykreslení bitmapy (představované objektem typu SDLSurface), si podrobněji popíšeme v navazující části tohoto seriálu. Druhý příkaz slouží pro vykreslení obdélníku vyplněného zadanou barvou. Veškeré vykreslování lze provést na libovolný objekt typu SDLSurface, přičemž i samotná obrazovka (přesněji řečeno buď přední nebo zadní buffer) je představována objektem tohoto typu. Ve druhém demonstračním příkladu se nejprve inicializuje grafický režim stejným způsobem, jako tomu bylo v příkladu prvním, ovšem s tím rozdílem, že nyní využijeme návratovou hodnotu statické metody SDLVideo.setVideoMode(). Touto hodnotou je již zmíněný objekt typu SDLSurface, který v tomto případě představuje přední buffer (nepovolili jsme totiž doublebuffering).
Následně se v metodě drawOnScreen() provede vykreslení obdélníku pomocí metody SDLSurface.fillRect(), které se předá objekt typu SDLRect obsahující informace o geometrii vyplňovaného obdélníku (pozice na obrazovce plus rozměry) a taktéž barva, kterou se má obdélník vyplnit. Barva je představována proměnnou typu long a pro získání skutečné hodnoty barvy se používá metoda SDLSurface.mapRGB(), která zajistí, že se výpočet barvy provede s ohledem na formát pixelů uložených v bitmapě nebo ve framebufferu. To mj. znamená, že v případě použití grafického režimu s jinou bitovou hloubkou vrátí tato metoda odlišnou hodnotu. Poslední metodou, kterou je nutné při vykreslování zavolat, je SDLSurface.flip(), a to i v případě, že není explicitně vyžadován double buffering.
Následuje výpis zdrojového kódu druhého demonstračního příkladu:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLVideo; import sdljava.video.SDLSurface; import sdljava.video.SDLRect; /** * Druhy demonstracni priklad vyuzivajici knihovnu sdljava. * Po spusteni se provede prepnuti do grafickeho rezimu 800x600x16 * Po inicializaci grafickeho rezimu se * provede vykresleni obdelniku a po peti sekundach se program ukonci. */ public class SDLTest2 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_WIDTH = 800; /** * Vertikalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_HEIGHT = 600; /** * Bitova hloubka vybraneho grafickeho rezimu. */ private static final int GFX_BPP = 16; /** * Vykresleni obdelniku na obrazovku. */ private static void drawOnScreen(SDLSurface screen) throws SDLException { // ziskat rozmery obrazovky final int width = screen.getWidth(); final int height = screen.getHeight(); // vypocitat barvu obdelniku final long color = screen.mapRGB(64, 255, 255); final SDLRect rect = new SDLRect(width >> 2, height >> 2, width >> 1, height >> 1); // vykreslit obdelnik screen.fillRect(rect, color); // nutno volat i v pripade, ze neni pouzit double buffering screen.flip(); } /** * Spusteni demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL. SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace celoobrazovkoveho grafickeho rezimu SDLSurface screen = SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, SDLVideo.SDL_FULLSCREEN); drawOnScreen(screen); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim SDLMain.quit(); } } }
7. Třetí demonstrační příklad – double buffering
Třetí demonstrační příklad je prakticky totožný s příkladem druhým až na jednu důležitou maličkost: při inicializaci grafického režimu je při volání metody SDLVideo.setVideoMode() požadováno využití double bufferingu, což znamená, že se v obrazové paměti grafického akcelerátoru budou alokovat dva buffery s rozlišením 800×600 pixelů a barvovou hloubkou 16bpp. První buffer bude přední (front buffer), který bude viditelný na obrazovce, zatímco druhý buffer bude zadní (back buffer) a právě do něj bude prováděno vykreslování. S využitím metody SDLSurface.flip() dojde k prohození funkcí obou bufferů. Povšimněte si, že při použití knihovny SDLJava je zapnutí double bufferingu velmi jednoduché, protože vyžaduje pouze předání bitového příznaku do metody SDLVideo.setVideoMode(), zatímco v případě využití AWT či Swingu bylo nutné použít třídu BufferStrategy a navíc ještě změnit veškeré vykreslovací rutiny tak, aby se správně využíval přední a zadní buffer, což obecně znamená zásah do celého grafického subsystému vyvíjené aplikace.
Výpis zdrojového kódu třetího demonstračního příkladu:
import sdljava.SDLMain; import sdljava.SDLException; import sdljava.video.SDLVideo; import sdljava.video.SDLSurface; import sdljava.video.SDLRect; /** * Druhy demonstracni priklad vyuzivajici knihovnu sdljava. * Po spusteni se provede prepnuti do grafickeho rezimu 800x600x16 * s podporou double bufferingu. Po inicializaci grafickeho rezimu se * provede vykresleni obdelniku, prohozeno obou bufferu a po peti * sekundach se program ukonci. */ public class SDLTest3 { /** * Horizontalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_WIDTH = 800; /** * Vertikalni rozliseni vybraneho grafickeho rezimu. */ private static final int GFX_HEIGHT = 600; /** * Bitova hloubka vybraneho grafickeho rezimu. */ private static final int GFX_BPP = 16; /** * Vykresleni obdelniku na obrazovku. */ private static void drawOnScreen(SDLSurface screen) throws SDLException { // ziskat rozmery obrazovky final int width = screen.getWidth(); final int height = screen.getHeight(); // vypocitat barvu obdelniku final long color = screen.mapRGB(64, 255, 255); final SDLRect rect = new SDLRect(width >> 2, height >> 2, width >> 1, height >> 1); // vykreslit obdelnik screen.fillRect(rect, color); // nutno volat i v pripade, ze neni pouzit double buffering screen.flip(); } /** * Spusteni demonstracniho prikladu. */ public static void main(String[] args) { try { // inicializace video subsystemu knihovny SDL. SDLMain.init(SDLMain.SDL_INIT_VIDEO); // inicializace celoobrazovkoveho grafickeho rezimu // s podporou double bufferingu SDLSurface screen = SDLVideo.setVideoMode(GFX_WIDTH, GFX_HEIGHT, GFX_BPP, SDLVideo.SDL_DOUBLEBUF | SDLVideo.SDL_FULLSCREEN); drawOnScreen(screen); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } finally { // musime obnovit puvodni graficky rezim SDLMain.quit(); } } }
Překlad a spuštění se provede naprosto stejným způsobem, jako tomu bylo v prvním demonstračním příkladu.
8. Repositář se zdrojovými kódy všech tří dnešních demonstračních příkladů
Všechny tři dnešní demonstrační příklady byly společně s podpůrnými skripty určenými pro jejich překlad a následné spuštění uloženy do Mercurial repositáře dostupného na adrese http://icedtea.classpath.org/people/ptisnovs/jvm-tools/. Ke každému příkladu jsou přidány čtyři skripty – skript SDLTestX_compile.sh slouží k překladu příkladu v případě, že se používá lokální kopie knihovny SDLJava, skript SDLTestX_compile_sys.sh pro překlad proti knihovně nainstalované v adresáři /usr/lib64/, skript SDLTestX_run.sh lze použít pro spuštění příkladu společně s lokální kopií SDLJava a konečně skript nazvaný SDLTestX_run_sys.sh slouží pro spuštění příkladu v případě, že je SDLJava nainstalovaná v systému. Z těchto skriptů lze snadno odvodit i další varianty, k nimž může v praxi dojít:
9. Odkazy na Internetu
- SDL Home Page
http://www.libsdl.org/ - SDL Language Bindings
http://www.libsdl.org/languages.php - SDL version 1.2.15
http://www.libsdl.org/download-1.2.php - SDL version 2.0.1
http://www.libsdl.org/download-2.0.php - sdljava Home Page
http://sdljava.sourceforge.net/ - sdljava Download Page
http://sdljava.sourceforge.net/download_sdljava.html - sdljava verze 0.9.1
http://sourceforge.net/projects/sdljava/files/sdljava/0.9.1/ - sdljava JavaDoc
http://sdljava.sourceforge.net/docs/api/ - Cross-platform games development (part 1)
http://renatoc.wait4.org/2010/02/04/cross-platform-games-development-part-1/ - Cross-platform games development (part 2)
http://renatoc.wait4.org/tag/sdljava/ - sdljava pro Fedoru 18
http://koji.fedoraproject.org/koji/buildinfo?buildID=344191 - sdljava pro Fedoru 19
http://koji.fedoraproject.org/koji/buildinfo?buildID=405746 - sdljava pro Fedoru 20
http://koji.fedoraproject.org/koji/buildinfo?buildID=453044 - Class java.awt.Frame (JDK7)
http://docs.oracle.com/javase/7/docs/api/java/awt/Frame.html - Class java.awt.Canvas (JDK7)
http://docs.oracle.com/javase/7/docs/api/java/awt/Canvas.html - Class java.awt.image.BufferStrategy (JDK6)
http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferStrategy.html - Class java.awt.Graphics
http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Graphics.html - Double Buffering and Page Flipping
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html - BufferStrategy and BufferCapabilities
http://docs.oracle.com/javase/tutorial/extra/fullscreen/bufferstrategy.html - Java:Tutorials: Double Buffering
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering - Double buffer in standard Java AWT
http://www.codeproject.com/Articles/2136/Double-buffer-in-standard-Java-AWT - Java 2D: Hardware Accelerating – Part 1 – Volatile Images
http://www.javalobby.org/forums/thread.jspa?threadID=16840&tstart=0 - Java 2D: Hardware Accelerating – Part 2 – Buffer Strategies
http://www.javalobby.org/java/forums/t16867.html - How does paintComponent work?
http://stackoverflow.com/questions/15544549/how-does-paintcomponent-work - A Swing Architecture Overview
http://www.oracle.com/technetwork/java/architecture-142923.html - Class javax.swing.JComponent
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html - Class java.awt.Component
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html - Class java.awt.Component.BltBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.BltBufferStrategy.html - Class java.awt.Component.FlipBufferStrategy
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.FlipBufferStrategy.html - Metoda java.awt.Component.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html#isDoubleBuffered() - Metoda javax.swing.JComponent.isDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#isDoubleBuffered() - Metoda javax.swing.JComponent.setDoubleBuffered()
http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#setDoubleBuffered(boolean) - Javadoc – třída GraphicsDevice
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsDevice.html - Javadoc – třída GraphicsEnvironment
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsEnvironment.html - Javadoc – třída GraphicsConfiguration
http://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsConfiguration.html - Javadoc – třída DisplayMode
http://docs.oracle.com/javase/7/docs/api/java/awt/DisplayMode.html - Lesson: Full-Screen Exclusive Mode API
http://docs.oracle.com/javase/tutorial/extra/fullscreen/ - Full-Screen Exclusive Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html - Display Mode
http://docs.oracle.com/javase/tutorial/extra/fullscreen/displaymode.html - Using the Full-Screen Exclusive Mode API in Java
http://www.developer.com/java/other/article.php/3609776/Using-the-Full-Screen-Exclusive-Mode-API-in-Java.htm - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - MultiMedia eXtensions
http://softpixel.com/~cwright/programming/simd/mmx.phpi - SSE (Streaming SIMD Extentions)
http://www.songho.ca/misc/sse/sse.html - Timothy A. Chagnon: SSE and SSE2
http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf - Intel corporation: Extending the Worldr's Most Popular Processor Architecture
http://download.intel.com/technology/architecture/new-instructions-paper.pdf - SIMD architectures:
http://arstechnica.com/old/content/2000/03/simd.ars/ - GC safe-point (or safepoint) and safe-region
http://xiao-feng.blogspot.cz/2008/01/gc-safe-point-and-safe-region.html - Safepoints in HotSpot JVM
http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html - Java theory and practice: Synchronization optimizations in Mustang
http://www.ibm.com/developerworks/java/library/j-jtp10185/ - How to build hsdis
http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/tools/hsdis/README - Java SE 6 Performance White Paper
http://www.oracle.com/technetwork/java/6-performance-137236.html - Lukas Stadler's Blog
http://classparser.blogspot.cz/2010/03/hsdis-i386dll.html - How to build hsdis-amd64.dll and hsdis-i386.dll on Windows
http://dropzone.nfshost.com/hsdis.htm - PrintAssembly
https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly - The Java Virtual Machine Specification: 3.14. Synchronization
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.14 - The Java Virtual Machine Specification: 8.3.1.4. volatile Fields
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4 - The Java Virtual Machine Specification: 17.4. Memory Model
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4 - The Java Virtual Machine Specification: 17.7. Non-atomic Treatment of double and long
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7 - Open Source ByteCode Libraries in Java
http://java-source.net/open-source/bytecode-libraries - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - BCEL Home page
http://commons.apache.org/bcel/ - Byte Code Engineering Library (před verzí 5.0)
http://bcel.sourceforge.net/ - Byte Code Engineering Library (verze >= 5.0)
http://commons.apache.org/proper/commons-bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - Javassist
http://www.jboss.org/javassist/ - Byteman
http://www.jboss.org/byteman - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - jclasslib bytecode viewer
http://www.ej-technologies.com/products/jclasslib/overview.html