Czterej jeźdźcy apokalipsy gdy Armagedon w JVM nadchodzi.
• 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
Ale niekoniecznie :)
Opowieść czas zacząć
Pewnego pięknego zimowego wieczorugdzieś w Krakowie, kilka lat temu
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
apt-get install sysstat
apt-get install strace
apt-get install sysdig
sar -d -R 1strace -f -T -p666
A mówiła mama nie zaglądać za zamknięte drzwi?
gdywtem,nagle
iznienacka ...
Z pyłu, sadzy
i dymu, pierwszy jeździec się wyłonił
A imię jego
Garbage Collector
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
Trade offs, stupid!
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
Input / Output
Block deviceDevice driver
IO scheduler (merge/sort)
I/O request
%iowaitDevice queue size
Time spent on the queue
iostat x d sda 1
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
qutim
Czas który JVM traci na oczekiwanie na operacje IO
select() (POSIX)epoll() (Linux)kqueue (*BSD)/dev/poll
syscallrequests a service from
kernel
userspacekernelspace
CPU privileged mode
glibc
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();
java.nio
Event loops
Reactor pattern
Nie bądź głupiUżyj
netty.io
Bufory IO pomiędzykernel space
Iuser space
Operacje IO wymagają wielu operacjiKopiowania pomiędzy userspace i kernelspace
DMAmmap()
MMU
Here was slide about
Memory mapped files & page faults,
But somebody removed it :)
… and here was slide about
Vectored IO
But somebody else removed it :)
kernel-user space „zero copy”
FileChannel#transferTo()
wewnątrz JVM „zero copy”
użyj Netty, serio
CompositeByteBuf
Trade offs, stupid!
Blokować?
Nie blokuj gdy,Dużo klientów masz
Blokuj gdy,Strumienie przetwarzasz
CPUs and hard drives are really good at
sequential reading/writing
Use it
I grom potężny pazurem swym nieboskłon na strzępy rozdarł
trzeci jeździec się wyłoniłA imię jego
synchronized
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}
WaitingIs
waste
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
Atomic operations are
getting faster and fasterWith every new CPU
But we are not there yet!
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
Just In Time compiler
Adaptive runtime
Based on profiling dataSlower startup times
Slower peek peformance(in some cases*)
JIT (Just in Time)HotSpot
Vs
AOT (Ahead of Time)(www.excelsiorjet.com)
Interpreter
C1 compiler
C2 compiler
OSR (on stack replacement)
deoptimization
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;}
Inline cache
Inline depth
Recursive inline
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
But first few words about
„fat”
and
„thin” locks
JVM uses futexA „mostly” userspace lock
based on atomic value and wait queue
Unless
high contentionwhich forces futex
to use kernelspacemutex
WAT?
Daleko jeszcze?
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
Let the eternal stream of byte codeFlows through your body