4Developers 2015: Czterej jeźdźcy apokalipsy, gdy Armagedon w JVM nadchodzi. - Jarosław Pałka
Transcript of 4Developers 2015: Czterej jeźdźcy apokalipsy, gdy Armagedon w JVM nadchodzi. - Jarosław Pałka
• chief architect @ Lumesse• owner/founder/one man orchestra @
symentis.pl• blogger @ geekyprimitives.wordpress.com• philosopher @ twitter:j_palka• code mangler @ bitbucket:kcrimson &
github:jpalka• evil emperor @ 4developers conf/architecture
track• restrained Padawan @ church of JVM
Celem tej prezentacji jest pokazanie Technik, których na co dzień nie będziecie
Stosować
Ten materiał zakłada, że na co dzień nie zgłębiacie terenów przygranicznych
System operacyjny/maszyna wirtualna
Zaprezentowane poniżej informacje i fakty mogą trwale odmienić wasze postrzeganie
rzeczywistości
Dopiero zaczynasz z JVM?Zachwycisz się złożonością
Masz już za sobą pierwszy pad produkcji?Przeklniesz złożoność JVM
Chcesz wiedzieć więcej jak to wszystko działa?
Ta prezentacja łagodnie wprowadzi Cię w terminologię i podstawy
Moją opowieść będę snuł wokół OpenJDK 8
isystemu operacyjnego Linux
Część z tych rzeczy może być prawdą dla innych
JDK i OS
O godzinie 4.03Gdy nadzieja już dawno opuściła biuro
A zdrowy rozsądek już dawno wyskoczył za okno
hg clone http://hg.openjdk.java.net/jdk8/jdk8
Wiele zrobiono i napisano o automatycznymzarządzaniu pamięcią w JVM
Gdy już ustawisz wszystkie parametryi
przełączniki A
GC nadal będzie zniewalało twój CPU
Jedyne co pozostaje to „off heap memory”
java.nio.ByteBuffer.allocateDirect()
„may reside outside of garbage collected heap”So called C-heap
Makes famous sun.misc.Unsafe a little bit saferAnd slower:)
But let's talk aboutsun.misc.Unsafe.allocateMemory
Allocation and deallocation is really expensive
Mostly because of costly JNI calls
and NMT (native memory tracking)
Mail thread@hotspot-devUnsafe allocate
Calls OS malloc functionhotspot/src/share/vm/prims/unsafe.cpp
UNSAFE_ENTRY(jlong, Unsafe_AllocateMemory(JNIEnv *env, jobject unsafe, jlong size)) UnsafeWrapper("Unsafe_AllocateMemory"); size_t sz = (size_t)size; if (sz != (julong)size || size < 0) { THROW_0(vmSymbols::java_lang_IllegalArgumentException()); } if (sz == 0) { return 0; } sz = round_to(sz, HeapWordSize); void* x = os::malloc(sz); if (x == NULL) { THROW_0(vmSymbols::java_lang_OutOfMemoryError()); } //Copy::fill_to_words((HeapWord*)x, sz / HeapWordSize); return addr_to_java(x);UNSAFE_END
Because it uses mallocYou can „easily” provide your own allocator
export LD_PRELOAD=mylib.so
jemalloc (look cassandra case)
Anyway, it all can end up with„core dump”
So be carefull
Or use wrappers
Tools to play withgithub:alexkasko/unsafe-tools
github:peter-lawrey/Java-Chronicleapache-directmemory
Who depends on unsafeehcache (with BigMemory)
hazelcast (with ElasticMemory)infinispan
lucenecassandra
Huge,really huge,
Tottaly hugedata structures
Beware!!!lifetime of objects
serialization/deserialization
… and then Jigsaw cameAnd changed the game
C-Heap APIbecause
people are actually using it(broken window)
Unsafe at any SpeedPublic sun.misc.Unsafe Replacement API
No plans for JDK9 so far
I ziemia się rozstąpiłaI ogień piekielny z ziemi wypełzać począł
drugi jeździec się wyłoniłA imię jego
avgqusz average queue length for this device
awaitaverage response time (ms) of IO requests to a
device.
svctimaverage time (ms) a device was servicing requests.
qutim = await svctim
sun.nio.ch.DefaultSelectorProvider if ("Linux".equals(osname)) { String osversion = AccessController.doPrivileged( new GetPropertyAction("os.version")); String[] vers = osversion.split("\\.", 0); if (vers.length >= 2) { try { int major = Integer.parseInt(vers[0]); int minor = Integer.parseInt(vers[1]); if (major > 2 || (major == 2 && minor >= 6)) { return new sun.nio.ch.EPollSelectorProvider(); } } catch (NumberFormatException x) { // format not recognized } } }
return new sun.nio.ch.PollSelectorProvider();
Bufory IO pomiędzykernel space
Iuser space
Operacje IO wymagają wielu operacjiKopiowania pomiędzy userspace i kernelspace
DMAmmap()
MMU
kernel-user space „zero copy”
FileChannel#transferTo()
wewnątrz JVM „zero copy”
użyj Netty, serio
CompositeByteBuf
Z pozoru wszystko wygląda niewinnie
%systemContext switches
Voluntary (IO wait, syscall*) Non voluntary (within time slice)
pidstat w t I p {pid}jstack {pid}
Non blocking algorithms
Wait-freedomKażda operacja zakończy się w z góry określonej
ilości kroków/ instrukcji
Lock-freedomPozwala na zagłodzienie wybranych wątków, Przynajmniej jeden wątek wykonuje operacje
Obstruction-freedom (optimistic concurrency)
Compare-and-swap
java.util.concurrent.atomic
„transakcyjne” metodyCopy on write
Persistent data structures
I wody z oceanów wystąpiły, A z nich bestie żarłoczne,
Człowiekowi nieprzychylneczwarty jeździec się wyłonił
A imię jego
Inlining
mother of all optimizations
C1 compilerinlines small methods
-XX:MaxInlineSize=35-XX:InlineSmallCode=2000
C2 compilerinlines „hot” methods
-XX:FreqInlineSize=325
public class Inline{
public int doubleAndSum(int x,y){ return makeDouble(x)+makeDouble(y); }
private int makeDouble(int x){ return x+x; }
//after inlining public int doubleAndSum(int x,y){ return (x+x)+(y+y); }
}
The easy part
private, static and final
The hard part
Polimorphism
Class hierarchy analisys
Deoptimization
Beware of megamorph
const char* StackWalkCompPolicy::shouldInline(methodHandle m, float freq, int cnt) { // Allows targeted inlining // positive filter: should send be inlined? returns NULL (--> yes) // or rejection msg int max_size = MaxInlineSize; int cost = m->code_size();
// Check for too many throws (and not too huge) if (m->interpreter_throwout_count() > InlineThrowCount && cost < InlineThrowMaxSize ) { return NULL; }
// bump the max size if the call is frequent if ((freq >= InlineFrequencyRatio) || (cnt >= InlineFrequencyCount)) { if (TraceFrequencyInlining) { tty->print("(Inlined frequent method)\n"); m->print(); } max_size = FreqInlineSize; } if (cost > max_size) { return (_msg = "too big"); } return NULL;}
other optimizations
remove redundant loads
loop unrollling
global value numbering
intrinsic
escape analisys
… And few others even more interesting
lock elision
lock coarsenning
adaptive locking
biased locking
JVM uses futexA „mostly” userspace lock
based on atomic value and wait queue
Unless
high contentionwhich forces futex
to use kernelspacemutex
What Every Programmer Should Know About Memory
Cpu Caches and Why You Care
Lock-Free Programming (or, Juggling Razor Blades)
brain food for hackers
Linux Device Drivers