I am writing a client-side Swing application (graphical font designer) on Java 5. Recently, I am running into java.lang.OutOfMemoryError: Java heap space error because I am not being conservative on memory usage. The user can open unlimited number of files, and the program keeps the opened objects in the memory. After a quick research I found Ergonomics in the 5.0 Java Virtual Machine and others saying on Windows machine the JVM defaults max heap size as 64MB.
Given this situation, how should I deal with this constraint?
I could increase the max heap size using command line option to java, but that would require figuring out available RAM and writing some launching program or script. Besides, increasing to some finite max does not ultimately get rid of the issue.
I could rewrite some of my code to persist objects to file system frequently (using database is the same thing) to free up the memory. It could work, but it's probably a lot work too.
If you could point me to details of above ideas or some alternatives like automatic virtual memory, extending heap size dynamically, that will be great.
Ultimately you always have a finite max of heap to use no matter what platform you are running on. In Windows 32 bit this is around 2GB (not specifically heap but total amount of memory per process). It just happens that Java chooses to make the default smaller (presumably so that the programmer can't create programs that have runaway memory allocation without running into this problem and having to examine exactly what they are doing).
So this given there are several approaches you could take to either determine what amount of memory you need or to reduce the amount of memory you are using. One common mistake with garbage collected languages such as Java or C# is to keep around references to objects that you no longer are using, or allocating many objects when you could reuse them instead. As long as objects have a reference to them they will continue to use heap space as the garbage collector will not delete them.
In this case you can use a Java memory profiler to determine what methods in your program are allocating large number of objects and then determine if there is a way to make sure they are no longer referenced, or to not allocate them in the first place. One option which I have used in the past is "JMP" http://www.khelekore.org/jmp/.
If you determine that you are allocating these objects for a reason and you need to keep around references (depending on what you are doing this might be the case), you will just need to increase the max heap size when you start the program. However, once you do the memory profiling and understand how your objects are getting allocated you should have a better idea about how much memory you need.
In general if you can't guarantee that your program will run in some finite amount of memory (perhaps depending on input size) you will always run into this problem. Only after exhausting all of this will you need to look into caching objects out to disk etc. At this point you should have a very good reason to say "I need Xgb of memory" for something and you can't work around it by improving your algorithms or memory allocation patterns. Generally this will only usually be the case for algorithms operating on large datasets (like a database or some scientific analysis program) and then techniques like caching and memory mapped IO become useful.
Run Java with the command-line option -Xmx, which sets the maximum size of the heap.
See here for details.
You could specify per project how much heap space your project wants
Following is for Eclipse Helios/Juno/Kepler:
Right mouse click on
Run As - Run Configuration - Arguments - Vm Arguments,
then add this
-Xmx2048m
Increasing the heap size is not a "fix" it is a "plaster", 100% temporary. It will crash again in somewhere else. To avoid these issues, write high performance code.
Use local variables wherever possible.
Make sure you select the correct object (EX: Selection between String, StringBuffer and StringBuilder)
Use a good code system for your program(EX: Using static variables VS non static variables)
Other stuff which could work on your code.
Try to move with multy THREADING
Big caveat ---- at my office, we were finding that (on some windows machines) we could not allocate more than 512m for Java heap. This turned out to be due to the Kaspersky anti-virus product installed on some of those machines. After uninstalling that AV product, we found we could allocate at least 1.6gb, i.e, -Xmx1600m (m is mandatory other wise it will lead to another error "Too small initial heap") works.
No idea if this happens with other AV products but presumably this is happening because the AV program is reserving a small block of memory in every address space, thereby preventing a single really large allocation.
I would like to add recommendations from oracle trouble shooting article.
Exception in thread thread_name: java.lang.OutOfMemoryError: Java heap space
The detail message Java heap space indicates object could not be allocated in the Java heap. This error does not necessarily imply a memory leak
Possible causes:
Simple configuration issue, where the specified heap size is insufficient for the application.
Application is unintentionally holding references to objects, and this prevents the objects from being garbage collected.
Excessive use of finalizers.
One other potential source of this error arises with applications that make excessive use of finalizers. If a class has a finalize method, then objects of that type do not have their space reclaimed at garbage collection time
After garbage collection, the objects are queued for finalization, which occurs at a later time. finalizers are executed by a daemon thread that services the finalization queue. If the finalizer thread cannot keep up with the finalization queue, then the Java heap could fill up and this type of OutOfMemoryError exception would be thrown.
One scenario that can cause this situation is when an application creates high-priority threads that cause the finalization queue to increase at a rate that is faster than the rate at which the finalizer thread is servicing that queue.
VM arguments worked for me in eclipse. If you are using eclipse version 3.4, do the following
go to Run --> Run Configurations --> then select the project under maven build --> then select the tab "JRE" --> then enter -Xmx1024m.
Alternatively you could do Run --> Run Configurations --> select the "JRE" tab --> then enter -Xmx1024m
This should increase the memory heap for all the builds/projects. The above memory size is 1 GB. You can optimize the way you want.
Yes, with -Xmx you can configure more memory for your JVM.
To be sure that you don't leak or waste memory. Take a heap dump and use the Eclipse Memory Analyzer to analyze your memory consumption.
Follow below steps:
Open catalina.sh from tomcat/bin.
Change JAVA_OPTS to
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1536m
-Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m
-XX:MaxPermSize=256m -XX:+DisableExplicitGC"
Restart your tomcat
By default for development JVM uses small size and small config for other performance related features. But for production you can tune e.g. (In addition it Application Server specific config can exist) -> (If there still isn't enough memory to satisfy the request and the heap has already reached the maximum size, an OutOfMemoryError will occur)
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
-Xss<size> set java thread stack size
-XX:ParallelGCThreads=8
-XX:+CMSClassUnloadingEnabled
-XX:InitiatingHeapOccupancyPercent=70
-XX:+UnlockDiagnosticVMOptions
-XX:+UseConcMarkSweepGC
-Xms512m
-Xmx8192m
-XX:MaxPermSize=256m (in java 8 optional)
For example: On linux Platform for production mode preferable settings.
After downloading and configuring server with this way http://www.ehowstuff.com/how-to-install-and-setup-apache-tomcat-8-on-centos-7-1-rhel-7/
1.create setenv.sh file on folder /opt/tomcat/bin/
touch /opt/tomcat/bin/setenv.sh
2.Open and write this params for setting preferable mode.
nano /opt/tomcat/bin/setenv.sh
export CATALINA_OPTS="$CATALINA_OPTS -XX:ParallelGCThreads=8"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+CMSClassUnloadingEnabled"
export CATALINA_OPTS="$CATALINA_OPTS -XX:InitiatingHeapOccupancyPercent=70"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UnlockDiagnosticVMOptions"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseConcMarkSweepGC"
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx8192m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxMetaspaceSize=256M"
3.service tomcat restart
Note that the JVM uses more memory than just the heap. For example
Java methods, thread stacks and native handles are allocated in memory
separate from the heap, as well as JVM internal data structures.
I read somewhere else that you can try - catch java.lang.OutOfMemoryError and on the catch block, you can free all resources that you know might use a lot of memory, close connections and so forth, then do a System.gc() then re-try whatever you were going to do.
Another way is this although, i don't know whether this would work, but I am currently testing whether it will work on my application.
The Idea is to do Garbage collection by calling System.gc() which is known to increase free memory. You can keep checking this after a memory gobbling code executes.
//Mimimum acceptable free memory you think your app needs
long minRunningMemory = (1024*1024);
Runtime runtime = Runtime.getRuntime();
if(runtime.freeMemory()<minRunningMemory)
System.gc();
Easy way to solve OutOfMemoryError in java is to increase the maximum heap size by using JVM options -Xmx512M, this will immediately solve your OutOfMemoryError. This is my preferred solution when I get OutOfMemoryError in Eclipse, Maven or ANT while building project because based upon size of project you can easily ran out of Memory.
Here is an example of increasing maximum heap size of JVM, Also its better to keep -Xmx to -Xms ration either 1:1 or 1:1.5 if you are setting heap size in your java application.
export JVM_ARGS="-Xms1024m -Xmx1024m"
Reference Link
If you came here to search this issue from REACT NATIVE.
Then i guess you should do this
cd android/ && ./gradlew clean && cd ..
Add this line to your gradle.properties file
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
It should work. You can change MaxPermSize accordingly to fix your heap problem
I have faced same problem from java heap size.
I have two solutions if you are using java 5(1.5).
just install jdk1.6 and go to the preferences of eclipse and set the jre path of jav1 1.6 as you have installed.
Check your VM argument and let it be whatever it is.
just add one line below of all the arguments present in VM arguments as
-Xms512m -Xmx512m -XX:MaxPermSize=...m(192m).
I think it will work...
If you need to monitor your memory usage at runtime, the java.lang.management package offers MBeans that can be used to monitor the memory pools in your VM (eg, eden space, tenured generation etc), and also garbage collection behaviour.
The free heap space reported by these MBeans will vary greatly depending on GC behaviour, particularly if your application generates a lot of objects which are later GC-ed. One possible approach is to monitor the free heap space after each full-GC, which you may be able to use to make a decision on freeing up memory by persisting objects.
Ultimately, your best bet is to limit your memory retention as far as possible whilst performance remains acceptable. As a previous comment noted, memory is always limited, but your app should have a strategy for dealing with memory exhaustion.
In android studio add/change this line at the end of gradle.properties (Global Properties):
...
org.gradle.jvmargs=-XX\:MaxHeapSize\=1024m -Xmx1024m
if it doesn't work you can retry with bigger than 1024 heap size.
add the below code inside android/gradle.properties:
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true
Note that if you need this in a deployment situation, consider using Java WebStart (with an "ondisk" version, not the network one - possible in Java 6u10 and later) as it allows you to specify the various arguments to the JVM in a cross platform way.
Otherwise you will need an operating system specific launcher which sets the arguments you need.
In my case it solved by assigning more memory to Shared build process heap size in intellij settings.
Go to intellij settings > Compiler > Shared build process heap size
Regarding to netbeans, you could set max heap size to solve the problem.
Go to 'Run', then --> 'Set Project Configuration' --> 'Customise' --> 'run' of its popped up window --> 'VM Option' --> fill in '-Xms2048m -Xmx2048m'.
If you are using Android Studio just add these lines with gradle.properties file
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
Android Studio
File -> Invalidate Caches and Restart solved it for me :)
If this issue is happening in Wildfly 8 and JDK1.8,then we need to specify MaxMetaSpace settings instead of PermGen settings.
For example we need to add below configuration in setenv.sh file of wildfly.
JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=256M"
For more information, please check Wildfly Heap Issue
If you keep on allocating & keeping references to object, you will fill up any amount of memory you have.
One option is to do a transparent file close & open when they switch tabs (you only keep a pointer to the file, and when the user switches tab, you close & clean all the objects... it'll make the file change slower... but...), and maybe keep only 3 or 4 files on memory.
Other thing you should do is, when the user opens a file, load it, and intercept any OutOfMemoryError, then (as it is not possible to open the file) close that file, clean its objects and warn the user that he should close unused files.
Your idea of dynamically extending virtual memory doesn't solve the issue, for the machine is limited on resources, so you should be carefull & handle memory issues (or at least, be carefull with them).
A couple of hints i've seen with memory leaks is:
--> Keep on mind that if you put something into a collection and afterwards forget about it, you still have a strong reference to it, so nullify the collection, clean it or do something with it... if not you will find a memory leak difficult to find.
--> Maybe, using collections with weak references (weakhashmap...) can help with memory issues, but you must be carefull with it, for you might find that the object you look for has been collected.
--> Another idea i've found is to develope a persistent collection that stored on database objects least used and transparently loaded. This would probably be the best approach...
Java OOM Heap space issue can also arise when your DB connection pool got full.
I faced this issue because of my Hikari Connection pool (when upgraded to Spring boot 2.4.*) was full and not able to provide connections anymore (all active connections are still pending to fetch results from database).
Issue is some of our native queries in JPA Repositories contain ORDER BY ?#{#pageable} which takes a very long time to get results when upgraded.
Removed ORDER BY ?#{#pageable} from all the native queries in JPA repositories and OOM heap space issue along with connection pool issue got resolved.
If this error occurs right after execution of your junit tests, then you should execute Build -> Rebuild Project.
If this error comes up during APK generation in react-native, cd into the android folder in your project and do:
./gradlew clean
then
./gradlew assembleRelease
If error persists, then, restart your machine.
In Intellij, it worked for me just by giving the "Build Project"
If everything else fails, in addition to increasing the max heap size try also increasing the swap size. For Linux, as of now, relevant instructions can be found in https://linuxize.com/post/create-a-linux-swap-file/.
This can help if you're e.g. compiling something big in an embedded platform.
I have a 1.5G xml file, and I use a DOM java parser (after throw out this problem I know DOM is not a good tool for big data, while I am still curious about the problem below). My issue is "OutOfMemoryError: Java heap space", based on the answers already exist, I change the eclipse.ini -xms and -xmx size both to 8096m, and I show the heap status in eclispe window to monitor how much heap size has used. While when I run this code, it just used "80m/8096m" then throw out the "out memory" bug, I wonder why there is clearly huge space not used, i.e. "8096m - 80m ", but still get to out of memory.
I wonder why there is clearly huge space not used, i.e. "8096m - 80m ", but still get to out of memory.
You are misinterpreting something1. And (IMO) the most likely think is that you are confusing the memory used by your IDE (Eclipse) with the memory used to run your application.
Unless you are doing something strange (and inadvisable) your application is run in a separate JVM whose heap parameters are independent of the IDE heap parameters. Unsurprisingly (to me) actual the memory usage of your Eclipse IDE process is small ... because that's not where your application was running.
Tweaking the heap parameters for Eclipse makes no difference to the application JVM heap parameters! What you actually need to do is to set the heap parameters in the Eclipse launcher config for your application. Within Eclipse. Alternatively, launch the application by hand from the command prompt.
But in this case, I doubt that it will work. I would be very surprised if you could represent a 1.5 GB XML file as a DOM in an 8GB Java heap. The overheads of that form of representation are too large.
1 - If the Eclipse IDE itself was running out of memory, it would get horribly slow, and then crash. Been there. Seen that. It typically happens if you are developing or examining a very large code-base.
I have a Java app that imports another jar as a library and calls its main method as shown below. But someApp is a very large process and constantly throws an OutOfMemoryError. No matter what I set my Java apps heap size to, someApp does not seem to share the allocated memory.
try {
someApp.main(args);
} catch (Exception ex) {
}
How do I get someApp to allocate more heap space? Can I use processBuilder? What do I do?
Thanks.
As it stands at the moment, you're merely calling a class from another application within your own Java process. This is exactly the same as you'd do for calling a "library method" (the term has no technical difference, you're simply invoking a method on an object of a class that can be resolved by your classloader).
So right now, someApp is running in the same JVM as your own application, and will share its maximum heap size. This can be increase with the JVM argument -Xmx (e.g. -Xmx2048m for a 2GB max heap), though it sounds like you're doing this already withotu success.
It would be possible to launch someApp in a separate Java process, which would allow you to configure separate JVM arguments and thus give it a separate heap size.
However, I don't think this is going to help much. If you're unable to get this application to run in the same JVM, regardless of your heap limit, there's nothing that would suggest it would work in a difference JVM. For example, if you're running with a 2.5GB heap and still running out of memory, running your own app with a 0.5GB heap and spawning a separate JVM with 2GB heap will not solve the problem, as something is still running out of memory. (In fact, separate memory pools make an OOME slightly more likely since there are two distinct chunks of free space, whereas in the former case both applications can benefit from the same pool of free space).
I suggest you verify that your heap sizes really are being picked up (connecting via JMX using JConsole or JVisualVM will quickly let you see how big the max heap size is). If you're really still running out of memory with large heaps, it sounds like someApp has a memory leak (or a requirement for an even larger heap). Capturing a heap dump in this case, with the JVM argument -XX:+HeapDumpOnOutOfMemoryError, will allow you to inspect the heap with an external tool and determine what's filling the memory.
Hopefully you've simply failed to increase the heap size correctly, as if the application really is failing with a large heap there are no simple solutions.
Unless someApp itself is building a new process, this will already be in the same process as your calling code, so it should be affected by whatever heap configuration you've set when starting up the JVM.
Have you kept track of how much memory the process is actually taking?
This doesn't make sense, unless you're running into OS limitations on how much memory you can allocate to a single Java process on your OS (see Java maximum memory on Windows XP)
Short of that, the way you're invoking someApp, it acts as a regular library. The main method acts like any other method.
Have you tried debugging the OutOfMemoryError? There may be something obscure that the app doesn't like about being invoked from your application...
If the jar you are importing is authored by you and could be more efficient, then modify it. It sounds like the problem you are having is loading in a shotty package. If this is a 3rd party package and you are allowed to modify it, poke around in the code and find where there might be limitations, change it, and rebuild it.
What is the best way to debug java.lang.OutOfMemoryError exceptions?
When this happens to our application, our app server (Weblogic) generates a heap dump file. Should we use the heap dump file? Should we generate a Java thread dump? What exactly is the difference?
Update: What is the best way to generate thread dumps? Is kill -3 (our app runs on Solaris) the best way to kill the app and generate a thread dump? Is there a way to generate the thread dump but not kill the app?
Analyzing and fixing out-of-memory errors in Java is very simple.
In Java the objects that occupy memory are all linked to some other objects, forming a giant tree. The idea is to find the largest branches of the tree, which will usually point to a memory leak situation (in Java, you leak memory not when you forget to delete an object, but when you forget to forget the object, i.e. you keep a reference to it somewhere).
Step 1. Enable heap dumps at run time
Run your process with -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp
(It is safe to have these options always enabled. Adjust the path as needed, it must be writable by the java user)
Step 2. Reproduce the error
Let the application run until the OutOfMemoryError occurs.
The JVM will automatically write a file like java_pid12345.hprof.
Step 3. Fetch the dump
Copy java_pid12345.hprof to your PC (it will be at least as big as your maximum heap size, so can get quite big - gzip it if necessary).
Step 4. Open the dump file with IBM's Heap Analyzer or Eclipse's Memory Analyzer
The Heap Analyzer will present you with a tree of all objects that were alive at the time of the error.
Chances are it will point you directly at the problem when it opens.
Note: give HeapAnalyzer enough memory, since it needs to load your entire dump!
java -Xmx10g -jar ha456.jar
Step 5. Identify areas of largest heap use
Browse through the tree of objects and identify objects that are kept around unnecessarily.
Note it can also happen that all of the objects are necessary, which would mean you need a larger heap. Size and tune the heap appropriately.
Step 6. Fix your code
Make sure to only keep objects around that you actually need. Remove items from collections in a timely manner. Make sure to not keep references to objects that are no longer needed, only then can they be garbage-collected.
I've had success using a combination of Eclipse Memory Analyzer (MAT) and Java Visual VM to analyze heap dumps. MAT has some reports that you can run that give you a general idea of where to focus your efforts within your code. VisualVM has a better interface (in my opinion) for actually inspecting the contents of the various objects that you are interested in examining. It has a filter where you can have it display all instances of a particular class and see where they are referenced and what they reference themselves. It has been a while since I've used either tool for this they may have a closer feature set now. At the time using both worked well for me.
What is the best way to debug java.lang.OutOfMemoryError exceptions?
The OutOfMemoryError describes type of error in the message description. You have to check the description of the error message to handle the exception.
There are various root causes for out of memory exceptions. Refer to oracle documentation page for more details.
java.lang.OutOfMemoryError: Java heap space:
Cause: The detail message Java heap space indicates object could not be allocated in the Java heap.
java.lang.OutOfMemoryError: GC Overhead limit exceeded:
Cause: The detail message "GC overhead limit exceeded" indicates that the garbage collector is running all the time and Java program is making very slow progress
java.lang.OutOfMemoryError: Requested array size exceeds VM limit:
Cause: The detail message "Requested array size exceeds VM limit" indicates that the application (or APIs used by that application) attempted to allocate an array that is larger than the heap size.
java.lang.OutOfMemoryError: Metaspace:
Cause: Java class metadata (the virtual machines internal presentation of Java class) is allocated in native memory (referred to here as metaspace)
java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?:
Cause: The detail message "request size bytes for reason. Out of swap space?" appears to be an OutOfMemoryError exception. However, the Java HotSpot VM code reports this apparent exception when an allocation from the native heap failed and the native heap might be close to exhaustion
java.lang.OutOfMemoryError: Compressed class space
Cause: On 64-bit platforms a pointer to class metadata can be represented by a 32-bit offset (with UseCompressedOops). This is controlled by the command line flag UseCompressedClassPointers (on by default).
If the UseCompressedClassPointers is used, the amount of space available for class metadata is fixed at the amount CompressedClassSpaceSize. If the space needed for UseCompressedClassPointers exceeds CompressedClassSpaceSize, a java.lang.OutOfMemoryError with detail Compressed class space is thrown.
Note: There is more than one kind of class metadata - klass metadata and other metadata. Only klass metadata is stored in the space bounded by CompressedClassSpaceSize. The other metadata is stored in Metaspace.
Should we use the heap dump file? Should we generate a Java thread dump? What exactly is the difference?
Yes. You can use this heap heap dump file to debug the issue using profiling tools like visualvm or mat
You can use Thread dump to get further insight about status of threads.
Refer to this SE question to know the differenes:
Difference between javacore, thread dump and heap dump in Websphere
What is the best way to generate thread dumps? Is kill -3 (our app runs on Solaris) the best way to kill the app and generate a thread dump? Is there a way to generate the thread dump but not kill the app?
kill -3 <process_id> generates Thread dump and this command does not kill java process.
It is generally very difficult to debug OutOfMemoryError problems. I'd recommend using a profiling tool. JProfiler works pretty well. I've used it in the past and it can be very helpful, but I'm sure there are others that are at least as good.
To answer your specific questions:
A heap dump is a complete view of the entire heap, i.e. all objects that have been created with new. If you're running out of memory then this will be rather large. It shows you how many of each type of object you have.
A thread dump shows you the stack for each thread, showing you where in the code each thread is at the time of the dump. Remember that any thread could have caused the JVM to run out of memory but it could be a different thread that actually throws the error. For example, thread 1 allocates a byte array that fills up all available heap space, then thread 2 tries to allocate a 1-byte array and throws an error.
You can also use jmap/jhat to attach to a running Java process. These (family of) tools are really useful if you have to debug a live running application.
You can also leave jmap running as a cron task logging into a file which you can analyse later (It is something which we have found useful to debug a live memory leak)
jmap -histo:live <pid> | head -n <top N things to look for> > <output.log>
Jmap can also be used to generate a heap dump using the -dump option which can be read through the jhat.
See the following link for more details
http://www.lshift.net/blog/2006/03/08/java-memory-profiling-with-jmap-and-jhat
Here is another link to bookmark
http://java.sun.com/developer/technicalArticles/J2SE/monitoring/
It looks like IBM provides a tool for analyzing those heap dumps: http://www.alphaworks.ibm.com/tech/heaproots ; more at http://www-01.ibm.com/support/docview.wss?uid=swg21190476 .
Once you get a tool to look at the heap dump, look at any thread that was in the Running state in the thread stack. Its probably one of those that got the error. Sometimes the heap dump will tell you what thread had the error right at the top.
That should point you in the right direction. Then employ standard debugging techniques (logging, debugger, etc) to hone in on the problem. Use the Runtime class to get the current memory usage and log it as the method in or process in question executes.
I generally use Eclipse Memory Analyzer. It displays the suspected culprits (the objects which are occupying most of the heap dump) and different call hierarchies which is generating those objects. Once that mapping is there we can go back to the code and try to understand if there is any possible memory leak any where in the code path.
However, OOM doesn't always mean that there is a memory leak. It's always possible that the memory needed by an application during the stable state or under load is not available in the hardware/VM. For example, there could be a 32 bit Java process (max memory used ~ 4GB) where as the VM has just 3 GB. In such a case, initially the application may run fine, but OOM may be encountered as and when the memory requirement approaches 3GB.
As mentioned by others, capturing thread dump is not costly, but capturing heap dump is. I have observed that while capturing heap dump application (generally) freezes and only a kill followed by restart helps to recover.
I start my java code (1.6.0_16 in Vista) with the following params (among others) -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../logs. I run the code and I can see in the logs there are two OOM.
The first one I know cause I can see in the stdout that the hprof file is being created:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to ../logs\java_pid4604.hprof ...
Heap dump file created [37351818 bytes in 1.635 secs]
And then, towards the end of the code I get another OOM, I capture this, but I don't get a second hprof file created. Anybody knows why is that?? Is it because I have captured the OOM exception?
I wouldn't try to recover from an OutOfMemoryError as some objects might end up in an undefined state (just thinking about an ArrayList that couldn't allocate its array to store date for instance).
Regarding your question, I'd suspect that -XX:+HeapDumpOnOutOfMemoryError is only creating a single dump intentionally to prevent multiple heap dumps: just think about several threads throwing an OOME at the same time, causing a heap dump for each thrown exception.
As a summary: don't try to recover from OOME and don't expect the JVM to write more than a single heap dump. However, if you still feel the need to generate a heap dump, you could try to manually handle an OOME exception and call jmap to create a dump or use "-XX:+HeapDumpOnCtrlBreak" (not sure though, how to simulate CtrlBreak programmatically).
Out of memory generates only one dump-file on the first error. If you want to get more you can try jmap or keep jconsole on the jvm (version 6) then you can after everything crashed i.e in the morning create your own dump from jconsole (or your analyser tool of choice).
More on the dumping subject can be read in Eclipse MemoryAnalyser.