An overview of the

OutOfMemoryError, said is Java. Lang. OutOfMemoryError, is bringing in the JDK exception, as the name implies, say is out of memory, when a serious shortage of our system memory will throw this exception (PS: note that this is an Error, This is not an Exception, so when you catch an Exception, it is not an Exception. This is not an Exception, but it is not an Exception. For those of you who don’t know much about OutOfMemoryError, this article will certainly surprise you. Here are a few things you can learn from it:

  • Must OutOfMemoryError be loaded
  • When is OutOfMemoryError thrown
  • Will numerous instances of OutOfMemoryError be created
  • Why are most OutOfMemoryError exceptions stackless
  • How do we analyze such anomalies

OutOfMemoryError class loading

So OutOfMemoryError, which is the loading of this class, when is this class loaded? You might be quick to say that due to the lazy loading mechanism of Java classes, this class will not normally be loaded unless it is first loaded when we throw OutOfMemoryError. If our system never throws OutOfMemoryError, the class will never be loaded. Verbose: class-version: java-verbose: class-version: java-verbose: class-version See if OutOfMemoryError was loaded and you’ll find the following in the output:

[the Loaded Java. Lang. OutOfMemoryError from/Library/Java/JavaVirtualMachines jdk1.7.0 _79. JDK/Contents/Home/jre/lib/rt jar]Copy the code

This means that the class is actually loaded when the VM starts, so where is the JVM loaded? Look at the following methods:

bool universe_post_init() { ... // Setup preallocated OutOfMemoryError errors k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_OutOfMemoryError(), true, CHECK_false); k_h = instanceKlassHandle(THREAD, k); Universe::_out_of_memory_error_java_heap = k_h->allocate_instance(CHECK_false); Universe::_out_of_memory_error_metaspace = k_h->allocate_instance(CHECK_false); Universe::_out_of_memory_error_class_metaspace = k_h->allocate_instance(CHECK_false); Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false); Universe::_out_of_memory_error_gc_overhead_limit = k_h->allocate_instance(CHECK_false); Universe::_out_of_memory_error_realloc_objects = k_h->allocate_instance(CHECK_false); . if (! DumpSharedSpaces) { // These are the only Java fields that are currently set during shared space dumping. // We prefer to not handle this generally, so we always reinitialize these detail messages. Handle msg = java_lang_String::create_from_str("Java heap space", CHECK_false); java_lang_Throwable::set_message(Universe::_out_of_memory_error_java_heap, msg()); msg = java_lang_String::create_from_str("Metaspace", CHECK_false); java_lang_Throwable::set_message(Universe::_out_of_memory_error_metaspace, msg()); msg = java_lang_String::create_from_str("Compressed class space", CHECK_false); java_lang_Throwable::set_message(Universe::_out_of_memory_error_class_metaspace, msg()); msg = java_lang_String::create_from_str("Requested array size exceeds VM limit", CHECK_false); java_lang_Throwable::set_message(Universe::_out_of_memory_error_array_size, msg()); msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false); java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg()); msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK_false); java_lang_Throwable::set_message(Universe::_out_of_memory_error_realloc_objects, msg()); msg = java_lang_String::create_from_str("/ by zero", CHECK_false); java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg()); // Setup the array of errors that have preallocated backtrace k = Universe::_out_of_memory_error_java_heap->klass(); assert(k->name() == vmSymbols::java_lang_OutOfMemoryError(), "should be out of memory error"); k_h = instanceKlassHandle(THREAD, k); int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0; Universe::_preallocated_out_of_memory_error_array = oopFactory::new_objArray(k_h(), len, CHECK_false); for (int i=0; i<len; i++) { oop err = k_h->allocate_instance(CHECK_false); Handle err_h = Handle(THREAD, err); java_lang_Throwable::allocate_backtrace(err_h, CHECK_false); Universe::preallocated_out_of_memory_errors()->obj_at_put(i, err_h()); } Universe::_preallocated_out_of_memory_error_avail_count = (jint)len; }}Copy the code

The above code actually loads the OutOfMemoryError class during VM startup and creates several OutOfMemoryError objects. Each OutOfMemoryError object represents a memory overflow scenario. For example, OutOfMemoryError caused by insufficient Java heap space, or OutOfMemoryError caused by insufficient Metaspace, the above code is from JDK8, so you can see the contents of Metaspace, if it is before JDK8, You will see Perm’s OutOfMemoryError, but metaspace is not the focus of this article, so I will not discuss it. If you are interested, you can write an article about metsapce.

Can the agent intercept this class load

Who is familiar with the bytecode enhancement, can be conditioned to think whether can intercept to this class of loading, so that we can do something such as memory leak monitoring what of, ha ha, I want to tell you is NO WAY, because of the WAY through the agent to listen the class loading process is begin after the completion of a vm initialization, And this kind of loading is in the process of vm initialization, so impossible to intercept to the Class loading, similar to it and Java. Lang. Object, Java. Lang. Class, etc.

Why load this class during VM startup

This question may read the content of the following you will experience, let’s keep in suspense. Including why these instance objects are created in advance will be explained later.

When an OutOfMemoryError is thrown

To throw an OutOfMemoryError, there must be a place where memory is allocated, either in the heap or in metsapce (or Perm before JDK8). The allocation strategy varies from place to place. Gc still cannot allocate and throws an exception.

However, using Heap allocation as an example, we can see how this process works:

In the correct case, the memory needed for object creation is allocated from the Eden area of the Heap. When Eden memory is insufficient, in some cases, allocation will be attempted in Old (for example, the memory to be allocated is very large). If the allocation fails, a YGC action will be triggered. After yGC is complete, we will try to allocate memory again. If the memory is still not enough, we will do a full GC (but soft reference will not be forcibly reclaimed), reclaim the old generation, and then allocate again. If the allocation is still insufficient, a full GC will be done to force the soft Reference to be reclaimed. If the allocation is still insufficient, an OutOfMemoryError will have to be thrown. This is how outofMemoryErrors are thrown by Heap allocation memory.

Could there be many OutOfMemoryError objects

Imagine a scenario where our code is bad enough and we have a memory leak, which means that after a certain point the system will gc whenever we create an object to allocate memory, but gc doesn’t work and throws OutOfMemoryError, That means an OutOfMemoryError object should be created and thrown every time this happens, meaning we’ll see an OutOfMemoryError with a stack thrown. Is that true? If so, why are the OutOfMemoryError objects created when the VM starts?

Do we care where the Java code throws the exception

If you don’t, please stay here for a minute and think about it before moving on.

The Java method that throws OutOfMemoryError is just a footstep, and it may or may not be the method that causes the memory leak, but it’s very unlikely. So you don’t have to worry about the stack that threw the exception.

Since can don’t care about the exception stack, that means this exception in fact it is not necessary to create a different every time, because they don’t need a stack, other things can be exactly the same, so back to the problem we mentioned before, why do you want to in the process of vm start to load the class, perhaps you already have the answer, During VM startup, we load the class and create several objects without a stack in the cache. All we need to do is set up a different prompt, and when we need to throw a specific type of OutOfMemoryError, we can just pull these objects out of the cache.

So there aren’t too many OutOfMemoryError objects, no matter how bad your code is. Of course, if you’re constantly new OutOfMemoryError() in your code, then I can’t say anything.

Why do we sometimes still see OutofMemoryErrors with stacks

There should be no OutOfMemoryError with a stack if you use the same OutOfMemoryError objects that were created when the JVM was started, but we do occasionally see exceptions with a stack, and if you’re careful, you might conclude that, Find up to four OutofMemoryErrors with stacks, after which you will see outofMemoryErrors without stacks.

This is actually reflected in the code we posted above. Finally, there is a for loop that creates OutOfMemoryError objects if we set StackTraceInThrowable to true (which is the default). Mean that we throw out the abnormal right there will be a stack, that according to PreallocatedOutOfMemoryErrorCount this parameter to decide in advance to create several OutOfMemoryError exception object, but unless the parameter under the debug version could be set up, It is a constant with a value of 4, so four OutOfMemoryError objects are created at JVM startup, but the stack of these objects can be set dynamically. For example, if an OutOfMemoryError is about to be thrown somewhere, one of the stored OutofMemoryErrors is fetched, the stack is filled, and thrown, and the object is used once. That is, the object will not be used again until the default OutOfMemoryError has been used up, and all subsequent outofMemoryErrors will be the ones that were cached in the first place.

This is why we see OutOfMemoryError exceptions with stacks up to four times, and most of the time we will see OutOfMemoryError objects without stacks.

How do I analyze OutOfMemoryError exceptions

Since see stack also doesn’t make sense, that can only start from the tip, we see this kind of abnormal, the first thing to determine exactly which chunk of memory what lead to the memory of, say, Perm, that will throw out the abnormal information of key information with a Perm, that we should focus on the size of the Perm, and the content in the Perm; Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump: Heap Dump

JVM Code Cache space is insufficient, resulting in slow service performance