Java Memory Management Margus Pala Java Fundamentals 03.11.2014
Agenda JVM memory Different garbage collectors References
Memory management in general Physical memory Swap space (page file) Virtual memory Each process has its own virtual address space OS will map virtual addresses to physical and swap Single virtual address maps to zero, one, or more than one physical address. Reserving memory does not mean actually allocating
JVM memory Address space Heap Non-heap or Native Heap and GC management Just-in-time (JIT) compiler JNI code and allocations Direct Byte Buffers Stack PermGen/metaspace
JVM memory II Heap Area for user objects Stack Per thread Local variables (reference and primitive) Call stack PermGen/MetaSpace All in one address space
JVM memory options -Xms512m Initial size of heap -Xmx1024m Maximum size of heap, the amount of address space that is reserved (not allocated) on startup. Heap can not grow larger than this. -XX:MaxPermSize=256m -Xss16m Max stack size
Garbage collection Opposite of manual memory management Objects are allocated from heap Allocated space is reclaimed automatically Object can be collected when there are no more references to it Usually no way to explicitly deallocate object GC comes and goes as it pleases
Good about GC Avoid bugs Avoids forgetting to free the memory Avoids double freeing memory Avoids using the already freed memory In Java No direct memory access Can't accidentally overwrite unrelated stack or heap regions.
Bad about GC Consumes resources No way to control Can cause unpredictable stalls A bit like magic
GC cost Stop the world GC may need to stop all other threads Long pauses hurt responsiveness GC takes longer with larger heaps
GC basics Basic principle Find objects that can not be accessed in the future Reclaim resources Reference counting What about circular references? Reachability Root set Active threads Local variables in main method Static variables in main class JNI References
Mark and sweep Starting from a "root set" mark all reachable objects Sweep all non-reachable objects Used by many real collectors Causes fragmentation and needs compacting
Fragmentation and compacting Fragmentation Happens when some objects are deleted Makes allocating memory expensive Free lists Compacting Usually done in every GC cycle Makes pauses longer Compact when fragmentation over limit Compact until fragmentation acceptable
Copying collector Typically collector has two areas active space and idle space Objects allocated to active space When full Move live objects from active space to idle space switch active space and idle space Repeat process Very efficient with small amount of live objects
Serial collector Simplest collector Both old and young Stop the world Single thread Compacting
Parallel collector Both old and young Best throughput Stop the world Multiple mark and sweep threads Compacting
Concurrent Mark and Sweep How it works Stop, mark roots alive Concurrently mark objects Stop, mark new objects Disadvantages Memory allocation errors if allocated space runs out More CPU cycles needed Complex to finetune
Concurrent Mark and Sweep Does not compact Concurrent mode failure Concurrent collection didn't finish before old generation got full Will trigger stop the world collection with serial collector Can also happen because of fragmentation You don't want this to happen
Generational GC Based on real world observation that most objects are short lived Memory regions Eden/Nursery objects start here Survivor object has survived first collection Tenured/Old long lived objects
Generational GC Usually new generation is small compared to old Objects get promoted from newer to older not vice versa Different collection strategies for generations
Oracle Hotspot generational GC Areas Eden 2x survivor Tenured New in Eden Copied to survivor and tenured Tenured M&S&C
G1 collector Garbage first Low pause, high throughput collector Concurrent and compacting Heap is partitioned into regions Global concurrent mark Collects mostly empty regions first Meets user defined pause times with high probability
IBM WebSphere GC Areas Nursery Allocate Survivor (same size as Allocate) Tenured New created in Allocate Large objects in non-generational or tenured Classes in heap
Oracle JRockit GC Keep area in the nursery. Start allocating outside the keep area Keep all objects in the keep area All live objects outside keep promoted to tenured Simple and efficient Only one copy Young area larger than others
Hotspot GC flags -XX:UseSerialGC is "Serial" + "Serial Old" -XX:UseParNewGC is "ParNew" + "Serial Old" -XX:UseParallelOldGC is "Parallel Scavenge" + "Parallel Old" -XX:UseParallelGC is "Parallel Scavenge" + "Serial Old" -XX:UseConcMarkSweepGC is "ParNew" + "CMS" + "Serial Old"
Hotspot GC flags A lot of options to tune various aspects (generation sizes, pause times etc.) For default values run: java -XX:+UnlockDiagnosticVMOptions -XX: +PrintFlagsFinal -version
To put it simply All new allocation happens in eden (unless the object is really large) Allocation is cheap When eden fills up, stop the world copy collection into the survivor space Freeing dead objects has zero cost After several collections survivors get promoted to the old generation Old generation GC is the expensive one
Monitoring GC Jconsole graphical tool Jps get pids of running java processes Jstat show info about running jvm jstat -gcutil 2576 1s S0 S1 E O P YGC YGCT FGC FGCT GCT 53.92 0.00 66.03 95.85 98.88 175348 2128.856 181 710.032 2838.888
Monitoring GC -verbose:gc -XX:+PrintGCTimeStamps -XX: +PrintGCDetails Why is my application not responding? 5562.069: [Full GC 5562.100: [Tenured: 818513K- >826236K(903872K), 335.3251660 secs] 1154710K- >826236K(1310592K), [Perm : 572671K->572671K(572672K)], 335.3774740 secs] [Times: user=4.72 sys=5.59, real=335.43 secs] 1148.695: [Full GC [PSYoungGen: 227712K->76103K(334144K)] [PSOldGen: 903868K->903868K(903872K)] 1131580K- >979971K(1238016K) [PSPermGen: 615356K->615356K(729472K)], 2.0278610 secs] [Times: user=2.06 sys=0.00, real=2.03 secs]
Heap dumps What happens when you run out of memory? -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps jmap -dump:file=format=b,dump.bin pid Eclipse memory analyzer jvisualvm
DO NOT USE IT Finalization finalize method is called before object is collected finalize is called only once for each object No guarantees when or whether objects are finalized GC overhead
Finalization public class Test { @Override public void finalize() { System.out.println("i'm dead"); } }
Finalization public class Test { static Test test; @Override public void finalize() { test = this; System.out.println("i refuse to die"); } }
References Strong reference Regular reference Soft reference Can be used for caches, guaranteed to be cleared before OutOfMemoryError is thrown Weak reference Keep reference without preventing GC from collecting referenced object Phantom reference
Soft reference import java.lang.ref.softreference; public class SoftCache<T> { private SoftReference<T> ref; public void set(t t) { ref = new SoftReference<T>(t); } public T get() { return ref.get(); } }
Weak reference public class WeakTest { //run with -verbose:gc public static void main(string... args) { WeakReference<Object> ref = new WeakReference<Object>(new Object()); for (int i = 0; ref.get()!= null; i++) { System.out.println(i); } } }
Which one works? obj = wr.get(); if (obj == null) { wr = new WeakReference(recreateIt()); //1 obj = wr.get(); //2 } ---------------------------------------------- obj = wr.get(); if (obj == null) { obj = recreateit(); //3 wr = new WeakReference(obj); //4 }
Phantom reference PhantomReference Phantom reference may not be retrieved: The get method of a phantom reference always returns null. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable. ReferenceQueue Reference will be added there when referent is collected PhantomReference always needs ReferenceQueue
Phantom reference import java.lang.ref.phantomreference; import java.lang.ref.referencequeue; public class MyRef<T> extends PhantomReference<T> { int x; public MyRef(T referent, int x, ReferenceQueue<T> q) { super(referent, q); this.x = x; } public String tostring() { return "MyRef[" + x + "]"; } }
Phantom reference 2 import java.lang.ref.reference; import java.lang.ref.referencequeue; public class PhantomTest { //run with -verbose:gc -Xmx2m public static void main(string... args) { final ReferenceQueue<Object> rq = new ReferenceQueue<Object>(); MyRef<Object> myref = new MyRef<Object>(new Object(), 8, rq); Reference<?> ref = null; for (int i = 0; (ref = rq.poll()) == null; i++) { System.out.println(i); // just to cause gc new Long(System.currentTimeMillis()).toString(); } System.out.println("collected " + ref); } }
Data structures WeakHashMap HashMap with weak keys (values are strong) No WeakIdentityHashMap in JDK ReferenceQueue Reference will be added there when referent is collected
Homework Calculating Fibonacci numbers Deadline is one week as usual This problem could be solved more efficiently and with less effort, though it would defeat the purpose of this exercise
Homework public class Fib1 { public static BigInteger fib(long n) { if (n == 0 n == 1) return BigInteger.ONE; BigInteger result = fib(n - 1).add(fib(n - 2)); return result; } public static void main(string... args) { int i = 0; BigInteger result = null; for (i = 0; i < 100000; i++) { // long start = System.currentTimeMillis(); result = fib(i); // long end = System.currentTimeMillis(); // System.out.println(i + " " + result + " " + (end - start)); } System.out.println("done"); } }
Homework Unfortunately this takes forever to run. As the same numbers are computed again and again caching would help. If I just cache all computed values in a HashMap then this will take a lot of memory, but I want to run it with -Xmx64m. Implement a cache based on one appropriate Reference type (PhantomReference, SoftReference or WeakReference) that would make this run fast with reasonable amount of memory. Template is added to homework9 in jf-skeleton, you only need to implement the MyCache class.
Internet references Java native memory http://goo.gl/obrdsy Garbage collection http://goo.gl/gy0xtb Hotspot VM Options http://goo.gl/r9qzzd References http://goo.gl/qbv3wh