Tuning ORM memory consumption [HHH-8682]
by Sanne Grinovero
Hi all,
from some performance tests we learned that a bottleneck for Hibernate
using applications is often identified in the amount of memory we
allocate at runtime, even considering the so called "short lived"
objects which usually are not a threat are actually too high.
Specifically, the highest consumer is the wild high amount of
instances of _org.hibernate.engine.spi.EntityKey_.
I think we have mainly two different strategies to attack this:
1# reduce the amount of EntityKey instances being allocated
2# reduce the size of each EntityKey instance
While 1# seems a wise move, I'll leave that to the ORM experts to
consider for future as it probably requires a broader knowledge of how
all components fit together.
So I'm attacking 2#, especially as I thought I could get some high win
in short time :)
To properly estimate the runtime size of each instance, I could simply
use the various reference tables of how much each pointer and
primitive takes, but there is actually some more complexity related to
the order in which the fields will be organized, and the requirement
of object alignment.
The rules aren't too hard to figure out the cost of a small value
object, but I'm actually using a tool which nicely dumps out a
reasonable estimate: "java object layout".
So this is the output of the current EntityKey implementation:
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
Running 64-bit HotSpot VM.
Using compressed references with 3-bit shift.
Objects are 8 bytes aligned.
org.hibernate.engine.spi.EntityKey
offset size type description
0 12 (assumed to be the object
header + first field alignment)
12 4 int EntityKey.hashCode
16 1 boolean EntityKey.isBatchLoadable
17 3 (alignment/padding gap)
20 4 Serializable EntityKey.identifier
24 4 String EntityKey.entityName
28 4 String EntityKey.rootEntityName
32 4 String EntityKey.tenantId
36 4 Type EntityKey.identifierType
40 4 SessionFactoryImplementor EntityKey.factory
44 4 (loss due to the next object alignment)
48 (object boundary, size estimate)
So that's 48 bytes per instance, and matches my expectations.
In our benchmark, we created about 200GB of such instances in 20
minutes, and the impact is of approximately 10% of the overall memory
pressure of the application.
I have an open pull request [2] which improves things, changing the
code to the following layout:
org.hibernate.engine.spi.EntityKey
offset size type description
0 12 (assumed to be the object header +
first field alignment)
12 4 int EntityKey.hashCode
16 4 Serializable EntityKey.identifier
20 4 String EntityKey.tenantId
24 4 EntityEssentials EntityKey.persister
28 4 (loss due to the next object alignment)
32 (object boundary, size estimate)
So we get from 48 to 32 bytes per instance; assuming the same
allocation that means saving about 33%, so some 60GB of memory
bandwith saved.
I think we could take it as a first step in the right direction, still
we're so very close to actually improve of 50%: there are 4 bytes per
instance "wasted" just because of alignment needs, if we could remove
just one more field we would save 8bytes.
In this example I removed the _tenantId_:
org.hibernate.engine.spi.EntityKey
offset size type description
0 12 (assumed to be the object header +
first field alignment)
12 4 int EntityKey.hashCode
16 4 Serializable EntityKey.identifier
20 4 EntityEssentials EntityKey.persister
24 (object boundary, size estimate)
So I would aim at implementing this, or alternatively if we really
can't remove the tenantId we could remove the (cached) hashCode:
org.hibernate.engine.spi.EntityKey
offset size type description
0 12 (assumed to be the object header +
first field alignment)
12 4 Serializable EntityKey.identifier
16 4 String EntityKey.tenantId
20 4 EntityEssentials EntityKey.persister
24 (object boundary, size estimate)
But that hashCode calculation is really hot so I would love to rather
remove the _tenantId_.
How can we remove the tenantId ?
I was thinking to have the tenandId included in the persister, so we'd
have a new interface:
public interface TenantLocalEntityPersister extends EntityPersister {
String getTenantId();
}
Implementors would have two fields:
EntityPersister ep; //shared across all tenants
String tenantId;
Then one single instance of such a TenantLocalEntityPersister would be
shared across all EntityKey instances associated to it, but also by
many other objects which need to shrink: for example
org.hibernate.engine.spi.EntityEntry needs to access the same concept,
and is the second highest consumer of memory (so next in line for a
similar refactoring to be done).
Would that be doable to refactor EntityPersister to have this concept
of per-tenant instance?
As a nice side-effect, I suspect it would also bring the cost of
managing multi-tenancy to zero for those applications which aren't
doing any multi-tenancy, while now there seems to be a cost paid by
all users.
Sanne
[1] https://github.com/jbaruch/java-object-layout
[2] https://github.com/hibernate/hibernate-orm/pull/633
12 years, 1 month
Meeting today
by Steve Ebersole
I won't be able to make the irc meeting today
12 years, 1 month
[OGM] RowKey vs. EntityKey
by Gunnar Morling
Hi,
This may be a noob question, but what is the difference between RowKey and
EntityKey in OGM?
Both seem to represent one row (by means of table name + key column names +
column values), albeit being implemented a bit differently. Could they be
merged into one class?
Thanks,
--Gunnar
12 years, 1 month
[OGM] Supporting Cassandra
by Gunnar Morling
Hi,
There is a pull request for adding support for Cassandra to OGM [1] which
has been created quite a long time ago.
Does anyone have details about it, e.g. what would need to be done in order
to integrate it? I guess it will need some work due to recent changes in
OGM and we might also benefit from younger additions to Cassandra itself.
Also query support should be doable now.
I'd be interested in taking this over but first would like to make sure I
better understand what's the current status of this dialect.
Thanks,
--Gunnar
[1] https://github.com/hibernate/hibernate-ogm/pull/164
12 years, 1 month
AnnotationBinder throws ArrayIndexOutOfBoundException
by Surendran D
Hello All,
I am implementing an Entity class as below
@Entity@Table(name=*"Employee"*)(a)IdClass(EmployeeEntityPK.*class*)*public
class *EmployeeEntity *extends *AbstractEntity {
//with no attributes only getter / setter
My AbstractEntity is a @MappedSuperClass with one @Id,@Column and other
@Columns defined
Also I have EmployeeEntityPK which has
@Id@Column(name = *"empId"*)*private *Integer *empId*;
When I deploy my application I get exception as
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547) [rt.jar:1.6.0_17]
at java.util.ArrayList.get(ArrayList.java:322) [rt.jar:1.6.0_17]
at
org.hibernate.cfg.AnnotationBinder.getUniqueIdPropertyFromBaseClass(AnnotationBinder.java:2576)
at
org.hibernate.cfg.AnnotationBinder.isIdClassPkOfTheAssociatedEntity(AnnotationBinder.java:925)
at
org.hibernate.cfg.AnnotationBinder.mapAsIdClass(AnnotationBinder.java:824)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:671)
AnnotationBinder.getUniqueIdPropertyFromBaseClass has a check as follows
*if *( elementsToProcess.getIdPropertyCount() == 1 ) {
which checks if my Entity has only one ID attribute, if so then
getsUniqueId from base class.
In my case I dont have any ID attribute in my EmployeeEntity so the I get
ArrayIndexOutOfBoundException.
Ideally in getUniqueIdPropertyFromBaseClass, baseClassElements should be
processed from AbstractEntity. Why its processing elements from
EmployeeEntity? Is this expected behaviour
I have added my source code to
https://github.com/surendrand/hibernate-entity-mapping for further reference
12 years, 1 month
Thinking about Forge 2 plugins
by Emmanuel Bernard
We probably should think about what it would mean to help people get
started with our projects using Forge. The Eclipse integration looks
very impressive and very much how I wish I could work to add layers.
I'll add it to the team meeting agenda.
Emmanuel
Date: Mon, 21 Oct 2013 18:27:12 -0400 (EDT)
From: Lincoln Baxter <lbaxter(a)redhat.com>
To: The Core
Subject: The Forge 2 philosophy in 4 minutes
Check out the video describing Forge 2 and where we are headed:
http://www.youtube.com/watch?v=Dpou-FWWatI
Just a quick update on the Forge project. This video will show you what we've been working on for the past while: namely a new architecture to allow extreme embed-ability, and real code re-use between addons (using our Modular container, called Furnace) https://github.com/forge/furnace (based on JBoss Modules and Maven). It does not go into great detail into many of these things, but is more of a high-level overview of the goals and features.
So what does this mean for your project?
1) Primarily, this means that you'll be able to work with us to create tools for your project that run in all of our supported environments and IDEs. Ideally this tooling should be focused on getting users started with your projects quickly, so if you're interested in having a Forge plugin for your project, please send me an email off list, and we will get the process started. We are currently preparing for the launch of our new website, so it will probably still be a few months before we can do any intensive project addon development with teams.
2) What this means in reality is that you can deliver tools that will run in JBDS and the command-line (and eventually IntelliJ, and NetBeans, and Web IDE), without worrying about coordination with an actual product release. Your release cycle is completely independent of ours. (Unless you are waiting for a new feature that is not yet released.)
To learn more about Forge 2, please visit our github repository: https://github.com/forge/core#jboss-forge-20
Expect to hear more from us soon :) We want *YOU*... and your projects of course :)
--
Lincoln Baxter, III
JBoss, by Red Hat
lbaxter(a)redhat.com
"If you want something, you'll find a way; if you don't, you'll find an excuse."
12 years, 1 month
[OGM] Hibernate OGM @ Devoxx
by Guillaume SCHEIBEL
Hello,
After SoftShake (and few JUGs), I'm proud (and kind of exited) to announce
my Tool In Action titled "a hint of NoSQL into my Java EE" has been
approved.
See you there :)
Guillaume
12 years, 1 month
HHH-8670 another EntityManager.find() not returning null question
by Scott Marlow
HHH-8670 is about EntityManager.find() not returning null when a runtime
exception is caught when performing the find(). Returning null when a
ClassCastException (or any other runtime exception) occurs seems
confusing to me, but I suppose that we could log a DEBUG warning (like
we did for EntityNotFoundException).
Does anyone disagree with changing Hibernate ORM to return null when a
runtime exception is caught during the EntityManager.find() operation?
Scott
12 years, 1 month