Thursday, November 7, 2013

Overview of java.lang.OutOfMemoryError

If your application's execution time becomes longer and longer, or if the operating system seems to be performing slower and slower, this could be an indication of a memory leak. In other words, virtual memory is being allocated but is not being returned when it is no longer needed. Eventually the application or the system runs out of memory, and the application terminates abnormally. In this post, we will look at different OutOfMemoryError error messages and their cause.

Before going further, we can see how we can print Garbage collection log to a file with the help of command line command.
Java -X



-Xloggc:file
Report on each garbage collection event, as with -verbose:gc, but log this data to file. In addition to the information -verbose:gc gives, each reported event will be preceeded by the time (in seconds) since the first garbage-collection event.
Always use a local file system for storage of this file to avoid stalling the JVM due to network latency. The file may be truncated in the case of a full file system and logging will continue on the truncated file. This option overrides -verbose:gc if both are given on the command line.
Example:
java -Xloggc:/root/temp/GC.log -XX:+PrintGCDateStamps test








One common indication of a memory leak is the java.lang.OutOfMemoryError error. This error is thrown when there is insufficient space to allocate an object in the Java heap or in a particular area of the heap. The garbage collector cannot make any further space available to accommodate a new object, and the heap cannot be expanded further.

When the java.lang.OutOfMemoryError error is thrown, a stack trace is printed also.

A java.lang.OutOfMemoryError can also be thrown by native library code when a native allocation cannot be satisfied, for example, if swap space is low.

An early step to diagnose an OutOfMemoryError is to determine what the error means. Does it mean that the Java heap is full, or does it mean that the native heap is full? To help you answer this question, the following subsections explain some of the possible error messages, with reference to the detail part of the message:

java.lang.OutOfMemoryError: GC overhead limit exceeded
The Garbage collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. 
If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.


java.lang.OutOfMemoryError: Java heap space
The detail message Java heap space indicates that an object could not be allocated in the Java heap. This error does not necessarily imply a memory leak. The problem can be as simple as a configuration issue, where the specified heap size (or the default size, if not specified) is insufficient for the application.

In other cases, and in particular for a long-lived application, the message might be an indication that the application is unintentionally holding references to objects, and this prevents the objects from being garbage collected. This is the Java language equivalent of a memory leak. Note that APIs that are called by an application could also be unintentionally holding object references.

One other potential source of OutOfMemoryError 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. Instead, after garbage collection the objects are queued for finalization, which occurs at a later time. In the Sun implementation, 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 OutOfMemoryError 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.
Basic introduction to Heap memory is here.


java.lang.OutOfMemoryError: PermGen space
First thing is what is PermGen space? The pool containing all the reflective data of the virtual machine itself, such as class and method objects. The size of this memory region is fixed, i.e. it does not change when the VM is running. The detail message PermGen space indicates that the permanent generation is full. The permanent generation is the area of the heap where class and method objects are stored. If an application loads a very large number of classes, then the size of the permanent generation might need to be increase. You can specify the size of this region with a commandline switch:
-XX:MaxPermSize .
If there's a problem with garbage collecting classes and if you keep loading new classes, the VM will run out of space in that memory region, even if there's plenty of memory available on the heap. To get more detail on PermGen space, click here.
Interned java.lang.String objects are no longer stored in the permanent generation (Java 7). The java.lang.String class maintains a pool of strings. When the intern method is invoked, the method checks the pool to see if an equal string is already in the pool. If there is, then the intern method returns it; otherwise it adds the string to the pool. In more precise terms, the java.lang.String.intern method is used to obtain the canonical representation of the string; the result is a reference to the same class instance that would be returned if that string appeared as a literal.
When this kind of error occurs, the text ClassLoader.defineClass might appear near the top of the stack trace that is printed. The jmap -permgen command prints statistics for the objects in the permanent generation and also information about internalized String instances.

I hope you have seen this error when you redeployed your application to an application server. As each application is loaded using its own classloader. Simply put, a classloader is a special class that loads .class files from jar files. When you undeploy the application, the classloader is discarded and it and all the classes that it loaded, should be garbage collected sooner or later. Somehow, something may hold on to the classloader however, and prevent it from being garbage collected. And that's what's causing the java.lang.OutOfMemoryError: PermGen space exception. PermGen error is no longer exist in Java 8

java.lang.OutOfMemoryError: unable to create new native thread
This is not a memory problem, but an operating system resource problem. You will receive this message if the JVM is asking a new thread from the OS and the underlying OS cannot allocate a new thread anymore. This limit is very platform dependent.
In JVM, each thread is allocated separate memory space called "thread stack", which is configured by JVM option "-Xss". The default value depends on OS/JVM. As number of threads increase, memory usage increases and can lead to 'out ofMemoryError'. Remember, the memory for threads is allocated on stack and not on Java Heap.
public class NativeThread {
 public static void main(String[] JavaLatte) {
  while(true){
   new Thread(new Runnable(){
    public void run() {
     try {
      Thread.sleep(20000000);
     } catch(InterruptedException e) { }
    }     
   }).start();
  }
 }

}

Sample Output
[root@pkumar temp]# /home/pkumar/jdk1.6.0_32/bin/java NativeThread
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:640)
at NativeThread.main(NativeThread.java:5)


java.lang.OutOfMemoryError: Requested array size exceeds VM limit
When you trying to allocate an array that is too large. This is because you're trying to create a very long String. Since arrays are indexed by an integer, an array cannot have more than Integer.MAX_VALUE elements. Even if the your heap size is very large, you won't be able to allocate an array that has more than Integer.MAX_VALUE elements, simply because you cannot index its elements using an Integer.
Some VMs reserve some header words in an array. The maximum "safe" number would be Integer.MAX_VALUE - 8 = 2 147 483 639. Attempts to allocate larger arrays may result in OOM

Java.util.ArrayList.class

      /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

public class ArraySize {
 public static void main(String[] JavaLatte) {
  int arr[] = new int[Integer.MAX_VALUE];
 }
}

Sample output
Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
at ArraySize.main(ArraySize.java:3)


If you know anyone who has started learning java, why not help them out! Just share this post with them.  Thanks for studying today!...

No comments:

Post a Comment