Java Memory How does Java manage memory? Why do I care? The Heap The heap is a large contiguous swath of memory reserved by the JVM at startup which it manages. All objects created by your application are allocated in the heap. What can I do when its not working? Preallocating the heap is one of the reasons that object allocation in Java can be faster than in C/C++. Instead of allocating memory, the JVM can just move pointers around when the application wants to create an object. However, preallocating all of this memory leads to comparatively slow startup times. The heap is usually broken up into generations. The eden space is where new objects are allocated. The vast majority of objects are created and die very quickly. These are harvested during minor compactions. These compactions move live objects to the survivor spaces and flatten the Eden space. The speed of this depends on the ratio of live objects in the space. Objects that make it to the survivor space and survive enough compactions are moved to the tenured generation. If they have survived this long they are likely to be around for a while. This space intentionally left blank(unallocated). The heap must be contiguous memory but the JVM only reserves it with the OS until it is needed. The tenured generation is cleaned during a major compaction which is as unpleasant as it sounds. It is slower than a minor compaction and can lead to noticable pauses, but we can deal with those later. The permanent generation stores non-application objects such as class definitions, methods etc. For really serious detail check out http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html#generations What is the GC actually doing? -verbose:gc -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 7.777: [GC 7.777: [ParNew: 16000K->2623K(18624K), 0.0331666 secs] 16000K->3270K(81280K), 0.0334059 secs] [Times: user=0.03 sys=0.01, real=0.03 secs] 14.664: [Full GC 14.664: [CMS: 646K->6070K(62656K), 0.1221005 secs] 16144K->6070K(81280K), [CMS Perm : 21247K->21233K(21248K)], 0.1225217 secs] [Times: user=0.11 sys=0.00, real=0.13 secs] 18.546: [GC 18.546: [ParNew: 16000K->2246K(18624K), 0.0137290 secs] 22070K->8317K(81280K), 0.0137942 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 26.226: [GC 26.226: [ParNew: 18246K->2498K(18624K), 0.0112402 secs] 24317K->9977K(81280K), 0.0113014 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 34.314: [GC 34.314: [ParNew: 18498K->1434K(18624K), 0.0059934 secs] 25977K->9765K(81280K), 0.0060549 secs] [Times: user=0.01 sys=0.01, real=0.00 secs] 46.280: [GC 46.280: [ParNew: 17434K->1787K(18624K), 0.0054596 secs] 25765K->10118K(81280K), 0.0055231 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 58.181: [GC 58.182: [ParNew: 17787K->1575K(18624K), 0.0052266 secs] 26118K->9906K(81280K), 0.0052865 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 70.167: [GC 70.167: [ParNew: 17575K->2131K(18624K), 0.0046365 secs] 25906K->10463K(81280K), 0.0046970 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 78.275: [GC 78.275: [ParNew: 18131K->1366K(18624K), 0.0064480 secs] 26463K->9809K(81280K), 0.0065118 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 90.210: [GC 90.210: [ParNew: 17366K->1660K(18624K), 0.0057945 secs] 25809K->10252K(81280K), 0.0058629 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] Learn by doing at http://kirk.blog-city.com/why_do_i_have_this_long_gc_pause.htm OutOfMemoryError What kind is it? 1) Heap memory error 2) Non-heap memory error 3) Native memory error You either legitimately need more heap space or your application is leaking. The fun part is finding out which one it is. PermGen space. Just set -XX:MaxPermSize higher (256MB is a huge amount) and move on with your day. Oh you poor, poor person. I'm so sorry. The OS told you to go away. The problem here is that it may not just be memory. This exception is thrown when the OS tells the JVM that it can't have any number of OS resources for whatever reason. Possible issues are: Unable to create native thread You're out of file handles Your heap is TOO BIG. It can crowd out the native side of the process on 32 bit machines. The whole process can only have 3GB+1GB for the kernel. So if your heap is 2.6GB everything else has to fit in 400MB. Every thread has a native stack allocated, the JVM itself, your birthday wish list, the letter from that girl you knew in highschool... it all has to fit in the native side of the process' memory. Wondering what is taking up all that space? Its time to take a dump. WHY IS THIS NOT THE DEFAULT?! JMX operation com.sun.management:type=HotSpotDiagnostic dumpHeap(String absoluteFilename, boolean collect first) jconsole or visualVM work well for this jmap -dump:live,format=b <pid> jmap -F -dump:live,format=b <pid> jmap -histo:live <pid> num #instances #bytes class name ---------------------------------------------- 1: 26062 3259184 2: 26062 3138720 3: 2111 2510488 4: 2111 1838000 5: 39712 1818624 6: 2026 1765792 7: 10319 715296 [C 8: 2327 428168 java.lang.Class 9: 2431 398352 [B 10: 9925 397000 java.lang.String 11: 3409 340552 [[I 12: 3428 272904 [S 13: 2432 222968 [I 14: 4298 206304 java.util.Hashtable$Entry 15: 971 183680 [Ljava.util.HashMap$Entry; If your application objects are near the top here you have serious problems Please dump the heap and no seriously, I'm not kidding around, dump the heap before I come over there. jmap comes with the JDK in the bin directory I've got the heap, now what? Eclipse MAT More complex than the federal budget but it comes with awesome sauce. http://www.eclipse.org/mat/ Garbage Collection The algorithms The thing that allows you to ignore all the details of memory management until it slows your application to a crawl and then you need to understand the details of garbage collection Background threads that run alongside your application, sometimes pausing them, to clean out objects which are no longer referenced from the heap. -XX:+UseSerialGC - Single threaded copy collector. http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html#available_collectors -XX:+UseParallelGC -XX:+UseParallelOldGC Good for maximum throughput when pauses are not an issue. Good for small heaps on single processor systems. -XX:+UseConcMarkSweepGC Although overall throughput is slightly lower than with ParallelGC CMS reduces pauses by collecting concurrent with your application threads as much as possible. This is only used on the tenured generation and live objects are not moved. This can lead to heap fragmentation over time which requires a major compaction to reorganize. Larger heaps can mitigate this. Still not good enough? But wait, there's more. http://www.fasterj.com/articles/G1.shtml G1 First available in 1.6.0_14 Clearing out empty generations is cheap. Copying small numbers of objects is ok. http://drdobbs.com/java/219401061 Divide heap into equal sized sections. Each one behaves like its own generation. G1 concurrently collects in each one and then determines which section will produce the most memory the fastest and only collects those. Each section can be left alone until its hopefully mostly empty when harvesting the live objects and reclaiming the whole section will be very fast. http://research.sun.com/jtech/pubs/04-g1-paper-ismm.pdf Pauses Throughput Fragmentation Major compactions can lead to unresposive applications for long periods of time, possibly tens of seconds or minutes for incredibly large heaps. G1 is supposed to help address this. You want as much CPU time as possible for your application. Never speak before you measure. How slow is copying objects really? The CMS collector doesn't move live objects so after a while your tenured generation starts to look like swiss cheese. Ergonomics Instead of specifying the heap size and generation size and compaction percentages blah blah blah blah Just tell the JVM what you want... -XX:MaxGCPauseMillis -XX:GCTimeRatio Desired maximum pause times Desired throughput Desired footprint max and min heap sizes It tries for these targets in this order modifying the unspecified ones to reach your specified goals. -XX:+HeapDumpOnOutOfMemoryError http://javabyexample.wisdomplug.com/java-concepts/34-core-java/60-different-types-of-outofmemoryerror-you-can-encounter-in-your-java-application.html Don't Pool objects that aren't expensive for a different reason Set variables to null to help the GC You know what helps the GC? Just do your thing. There's a lot of smart people trying to guess how you code and make the GC work for that. Don't outsmart them. System.gc() Similar to Serial but uses multiple threads and work stealing to utilize multiple processors. Only used on young generation Same algorithm but used on the tenured generation as well. Collects objects while your application threads are running. Stops all threads less than ParallelGC. Usually used with -XX:+ParNewGC to use paralell collector on young generation Good for minimum pauses Presentation by John Russell (jjrussell@gmail.com)