At work we had some heap usage issues with our J2EE/Flex based application. On a VM max heap of 1200mg, we were using 800mg right on startup. There was simply not enough memory to get some good performance of the app.
I did a memory dump of the heap and analyzed the objects that were not collected by the GC. It turned out that there were 400mg of char[] instances stuck in memory. All those strings where owned by Hibernate SessionFactory instances.
As I discovered, Hibernate caches all the SQL parts that it could use. (ex: for each mapped entity, it pre-builds the SELECT, INSERT, UPDATE statements, it caches the column names of each field, etc.) Because our database is very large, we have more than 200 entities in our SessionFactory, so it’s 70mg of memory that is uncollectable for each instance.
OK, 70mg is not a terrible price to pay, however, we have 6 databases that replicate that same tables and we have to use them all at the same time because the user can dynamically switch to the database he needs at runtime. So, here was 420mg of stuck heap memory.
Because there is no support to change the data source after a SessionFactory/Session is built, I had to implement a custom solution to fix the problem. The goal was to have only one SessionFactory that maps all the tables of our BD but where you could change the data source dynamically depending on the user choice.
In Hibernate, you can implement a custom ConnectionProvider. The implementer of that interface returns the JDBC connection to use. The problem is that you cannot pass parameters to a ConnectionProvider dynamically; you can only configure it once. So, I modified the Hibernate source code so that it’s possible to pass parameters to the ConnectionProvider.getConnection method.
Therefore, it becomes possible to create a new Session from the unique SessionFactory and dynamically bind the user’s data source to it.
A bit of warning however, when you do this, you have to disable the second level cache. Else, if you have rows with the same IDs across your databases, they won’t be differentiated in the cache, which is a big problem. There is surely a way to modify Hibernate in consequence, but this is left as an exercise to the reader.
Comments
Hibertate ... sweet ... Hibertate
Hibernate...You returned to your first love ;)