[x^2 for x in lst]

Java Performance - The Definitive Guide

Author: Scott Oaks

Review created: 2014-10-21

Något år efter sekelskiftet sedan läste jag en O'Reilly-bok som handlade om Java-prestanda och hur man kunde höja den. Boken hette helt enkelt Java Performance Tuning och var skriven av Jack Shirazi. Jag kommer ihåg att den bland annat gav tipset att man skulle skriva en egen String-klass och använda denna på de ställen där i18n inte var relevant.

Nu har det kommit ut en ny bok om Java-prestanda från O'Reilly. Den heter Java Performance - The Definitive Guide och innehåller inte några lika udda tips som det ovan. Boken är skriven av Scott Oaks som har jobbat med Java-prestanda på Sun/Oracle sedan 2001, så det är en kille som kan sitt ämne.

Boken inleds med en diskussion om vad prestanda är, vad man kan mäta när det gäller prestanda och hur man kan göra det. Detta är en mycket bra del i boken. Jag har svårt att komma ihåg de exakta definitionerna av latency, throughput och de övriga prestandarelaterade storheterna, så en repetition av dem är alltid välkommen. När det gäller hur man mäta prestanda så var den presenterade uppdeliningen i microbenchmarks (tänk enhetstest), macrobenchmarks (tester på det fullständiga systemet i en driftsmiljö) och mesobenchmarks (något mitt i mellan) ny för mig. Den är säkert vedertagen i prestandamärningskretsar, men jag hade inte hört talas om den förrut, så det var en ny, och bra, lärdom.

Efterföljande sektion i boken handlar om vilka verktyg som finns för att mäta prestanda och för att få en bättre bild av hur ett Java-program beter sig under körning. Det visar sig att det finns med en hel uppsjö bra sådana verktyg i JDK:n. Bland dessa kan nämnas jconsole, Java Mission Control, (JMC), jcmd, jstack och jinfo. De här verktygen går boken igenom tämligen grundligt. Den berättar också om andra verktyg, bland annat för att mäta CPU- och minnesförbrukning, som finns med i de vanligaste operativsystemen. Det här var ett mycket användbart avsnitt. Det var väldigt bra, i alla fall för mig, att få en överblick över vilka verktyg som finns för att mäta olika prestandarelaterade saker och hur man bör använda dem för att göra mätningar av olika slag.

Efter diskussionen om verktyg forstätter boken med ett avsnitt om de olika Java-kompilatorerna. Den går igenom vilka olika kompilatorer som finns, hur man skall välja mellan dem och och hur man kan justera dem för att passa just det program man vill exekvera. Jag visste att det fanns -client och -server flaggor som man kunde ange till java-kommandot, men hade inte egentligen tänkt så mycket på vad de innebär. Boken lärde mig att de specifierar olika kompilatorer: klientkompilatorn (C1) och serverkompilatorn (C2). Dessutom finns en flagga, -XX+TieredCompilation som gör att en kombination av de båda kompilatornerna används. Det som skiljer de olika kompilatorerna åt är efter hur många exekveringar av en kodsnutt som de kompilerar bytecode:n som kodsnutten består åt till maskinkod. Klientkompilatorn börjar kompilera kod tidigare än serverkompilatorn. Eftersom kompilerad kod exekverar fortare än okompilerad kod ger detta fördelen att kodsnutten kommer att exekvera snabbt i ett tidigare skede. Fördelen med att vänta med att kompilera är att kompilatorn då samlar på sig mer information om hur den skall optimera den genererade koden. När serverkompilatorn väl kompilerar en kodsnutt kommer den troligtvis att genererera maskinkod som exekverar snabbare är maskinkod producerad av klientkompilatorn. Vilket man föredrar, ganska snabb kod tidigt eller mycket snabb kod lite senare, är ofta en fråga om vilken typ av program som avses. Ett kortlivat program eller ett program med ett grafiskt användargränssnitt kan kanske tjäna på att använda klientkompilatorn medan ett långlivat serverprogram troligtvis tjänar på att använda serverkompilatorn.

Direkt efter den tämligen djupgående diskussionen om kompilatorer kastar sig boken in i en ännnu djupare diskussion angående minneshanering i allmänhet och skräpsamling (GC) i synnerhet. Hela fyra kapitel (av 12) handlar om detta. Man får bland annat lära sig ett det finns fyra olika GC-algoritmer (serial, throughput, CMS, G1) implementerade i JVM:en. På samma sätt som med kompilatorerna får man lära sig hur man anger vilken som skall användas och vad man skall tänka på när man väljer ut vilken man vill använda. Beskrivningarna som görs av de olika skräpsamlarna är väldigt ingående med exempel på hur de fungerar i olika situationer och för olika parameteruppsättningar.

Kapitlen om generell minneshantering behandlar bland annat verktyg för att än mer ingående undersöka minneshanteringen hos ett program samt de olika mått (shallow, deep, retained) som kan användas om man vill räkna på hur mycket minne som ett objekt av en viss klass tar. Boken tar även upp olika typer of referenser (weak, soft, phantom) och hur dessa kan användas för att inte undanhålla minne från att samlas upp i onödan och olika former av livscykelhantering för objekt (objektpooler, hantering mha ThreadLocal-teknik mm).

Avsnittet om minneshantering avslutas med ett kapitel om native sådan. Dvs vid vilka tillfällen som JVM:en allokerar icke-heap-minne, hur man kan mäta åtgången på sådant minne och vilka parametrar det finns att skruva på.

Så här långt i boken har det funnits väldigt få kodexempel. Texten har mest handlat om saker som har med själva JVM:en att göra och hur man kan anpassa den för att få bra prestanda. Resten av boken handlar mer om vad man skall tänka på när man kodar Java. Den hör delen är alltså inriktad på hur man forma sin kod för att den skall exekvera med så bra prestanda som möjligt. Följande ämnen behandlas:

  • Trådning/synkronisering
  • XML/JSON
  • Serialisering
  • Nätverksanrop
  • JDBC
  • JPA
  • Buffered I/O
  • Klassladdning
  • Slumptal
  • JNI
  • Exceptions
  • Stränghantering
  • Loggning
  • Collections
  • Lambdas/Streams

Som synes är det en ganska diger lista med ämnen som avhandlas. Det framkommer inte något direkt revolutionerande, men väl väldigt mycket matnyttig information och många konkreta tips.

Boken avslutas med ett appendix som listar alla de JVM-parametrar som gåtts igenom i boken (och de är många). Parametrarna är sorterade i grupper efter vad de styr. En grupp handlar om allmänna GC-inställningar, en annan om kompilatorinställningar och så vidare.

Vad tycker jag då om boken? Författaren gör en mycket grundlig genomgång av de olika ämnen som han behandlar. Vissa delar upplevde jag som lite torra, till exempel den mycket långa genomgången om hur de olika skräpsamligsalgoritmerna fungerade. Dock är även dessa avsnitt nyttiga att ha läst. Jag tänker inte låtsas som om jag kommer ihåg alla detaljer, men det känns bra att ha läst dem och förhoppningsvis kommer jag ihåg var jag skall leta efter information om jag någon gång skulle behöva fördjupa mig i dessa ämnen.

Avsnitten som tar upp olika verktyg för att mäta olika prestandarelaterade saker är mycket användbara. Det är väl även de delar av boken som tar upp olika tuning-parametrar för JVM:en, även om det är osannolikt att man kommer att använda så många av dessa i verkligheten. Appendixet som listar alla de genomgångna parametrarna tycker jag var en bra ide. Att kunna ögna igenom den listan i jakt på en parameter som är relaterad till något man vill optimera känns vettigt.

De delar av boken som behandlar hur man skall skriva Java-kod på prestandamässigt bra sätt är också mycket bra. Som jag skrev ovan presenteras inga silverkulor, men många bra tips om hur man bör skriva sin kod och hur man inte bör skriva den. Speciellt det sistnämnda känns bra att ha koll på. Något som var bra för självförtroendet var att inget av de kodmönster som jag brukar använda var med som dåligt exempel ;)

Något annat som var roligt att läsa var att Java-program som använder lambauttryck inte hade sämre prestanda än Java-program skrivna på traditionellt sätt. Tvärtom, visade boken på att vissa typer av program som använder stream:s exekverar rejält mycket snabbare än motsvarande program utan stream:s. Kul!

Sammanfattningsvis skulle jag vilja säga att Java Performance - The Definitive Guide är en mycket nyttig bok att läsa. Några av kapitlen om skräpsamlig och Java-kompilatorerna var lite seglästa, men tog man dem bara i lagom etapper var det inga problem att ta sig igenom dem också. Övriga delar av boken var relativt lättlästa och lättillgängliga.

Boken rekommederas helt klart till Java-kodare och personer som jobbar med drift av Java-program!

Betyg: 4 av 5.