Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronized Classloader calls from Hibernate

We are having a performance Issue in our project which seems to originate (at least in parts) from the way Hibernate uses the classloader. This was discovered in Java thread dumps which were taken during high load tests on our internal environment. The JVM dumped is the JVM of the Weblogic managed server which runs the application, and dumps were taken while the monitoring dashboard shows hogging threads and pending user requests.

Example:

"[ACTIVE] ExecuteThread: '126' for queue: 'weblogic.kernel.Default (self-tuning)'" daemon prio=10 tid=0x00007f2fe9486000 nid=0x663b waiting for monitor entry [0x00007f2faeae6000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:405)
    - waiting to lock <0x000000078c0d76b0> (a weblogic.utils.classloaders.GenericClassLoader)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at weblogic.utils.classloaders.GenericClassLoader.loadClass(GenericClassLoader.java:178)
    at org.hibernate.internal.util.ReflectHelper.classForName(ReflectHelper.java:187)
    at org.hibernate.internal.util.ReflectHelper.getConstantValue(ReflectHelper.java:278)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl$JavaConstantConverter.handleDotStructure(QueryTranslatorImpl.java:592)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl$JavaConstantConverter.visit(QueryTranslatorImpl.java:587)

What we can see in these thread dumps (using Samurai/TDA) is that there seem to be a great many threads at any time which are waiting for locks on the classloader. This classloader, provided by WLS, seems to be synchronized - which explains the locking/blocking thread pattern...

It seems Hibernate uses the classloader to evaluate expressions in queries. So I'm not sure the classloader calls actually load any new classes.

The problem is the number of calls to the classloader which appear to be going on all the time... At times I observed as much as 30% of the total number of threads (~30-40+ our of 130) waiting on getting a classloader lock!

--> It seems that the synchronization of the WLS classloader leads to a very high internal overhead when a high number of threads are trying to service a high user load (i.e. many Hibernate queries).

Is this behavior normal or are we doing something wrong?

Right now this synchronized classloader issue seems to be the main reason which limits the throughput of our application, leading to degrading performance under heavy load. Also the problem does not go away if we scale up CPU/memory or various WLS specific pools (like EJB/JDBC connections/...) -- as it is specific to the entire JVM we run our app in.

I'd much appreciate your input on the topic.


P.S.

Google seemed to show that we are not the first ones to encounter this issue (e.g. this mailing list question or this Oracle Support Question), but there is no real solution/explanation to this problem.

like image 743
fgysin Avatar asked Oct 28 '14 12:10

fgysin


People also ask

Is it possible to load a class by two ClassLoader?

A class is always identified using its fully qualified name (package. classname). So when a class is loaded into JVM, you have an entry as (package, classname, classloader). Therefore the same class can be loaded twice by two different ClassLoader instances.

How does ClassLoader work in Java?

A Java Class is stored in the form of byte code in a . class file after it is compiled. The ClassLoader loads the class of the Java program into memory when it is required. The ClassLoader is hierarchical and so if there is a request to load a class, it is delegated to the parent class loader.

What is ClassLoader in Java and what are types of ClassLoader in Java?

The Java ClassLoader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine. The Java run time system does not need to know about files and file systems because of classloaders. Java classes aren't loaded into memory all at once, but when required by an application.


2 Answers

The problem is that application programmers think that Class.forName() and Classloader.loadClass() are cheap operations like a new Object() would be. And application servers thinks that they are a rare startup operation.

For hibernate using criteria or dynamic generated JPQL can trigger this lock contention http://dimovelev.blogspot.dk/2015/02/performance-pitfalls-hibernate-criteria.html

like image 138
Hack Kampbjørn Avatar answered Sep 29 '22 20:09

Hack Kampbjørn


This issue was reported multiple times on Hibernate Jira:

  • HHH-1810
  • HHH-4959
  • HHH-10746
  • HHH-11246

Class.forName is not free. Depending on the underlying application server, it can cause lock contention as illustrated by Dimo Velev.

Pierre-Hugues Charbonneau has a similar analysis on this topic, which is a wonderful read as well.

The HHH-4959 Jira issue was fixed in Hibernate 5.2.6, and this should no longer be a problem.

like image 39
Vlad Mihalcea Avatar answered Sep 29 '22 22:09

Vlad Mihalcea