Hibernate Batch Fetch style recommendations


#1

Hello,

I’m working to upgrade my Hibernate version to 5.3. I’ve noticed that by default the legacy batch fetch style is being used by default (LegacyBatchingEntityLoader).

This style with a default batch fetch size of 50 and in combination with my model which contains hundreds of entities with different proxies is giving me a retained heap of 950 MB by the SessionFactoryImpl class once Hibernate is set up.

However, using the dynamic fetch style this retained size is reduced to 100MB…which is a considerable difference.

I would like to know:

  1. Why is the legacy style the default option?
  2. Do you have any kind of benchmark/recommendations that I can follow to decide which is the best approach to take?

Thanks in advance.


#2

Are you fetching 1GB of entities from the DB?

Before thinking of changing batch fetch size, try to address the amount of data you fetch. Do you really need so much data for your business use case.


#3

Hello,

thanks for the quick response. I’m not fetching entities. This problem is happening just when loading the model.

Here you can find a memory snapshot retrieved when my application starts, right after setting up Hibernate.

I’ve noticed that the greater amount of retained heap is taken by the LegacyBatchingEntityLoader instances.

Regards


#4

It takes 1.2 M our and there are only 24 instances. However, the heap is 1GB, so I guess it’s the Metamodel that takes so much memory. If you have thousand of classes, you need lot of memory to hold the Metamodel for that.


#5

Hello,

thanks! Some additional feedback to try to prove my point… this is the memory dump taken from my application before upgrading to Hibernate 5.3:

and this is the heap after the upgrade (the same of my previous post):

Please note the difference between the retained size of the SingleTableEntityPersister instances. In particular, the retained size of each SingleTableEntityPersister is coming from a map where each entry references the mentioned LegacyBatchingEntityLoader.


#6

And In addition, if I change the batch fetch style to “dynamic” instead of using the “legacy” one, I can see that the retained size of the SingleTableEntityPersister is decreased:

https://drive.google.com/open?id=1vWdkIB24HUCeHtlqcOlyPrZk18nNUouN

What do you think?


#7

@caristu Thanks for letting us know. I’ll send it to the mailing list so we can discuss what might have caused this memory increase and the best way to address it.


#8

Ok, thanks for the help!


#9

Hi, thanks for this, very useful!

Could you confirm which preview version exactly of Hibernate ORM 5.3 you’re using?

We switched the default bytecode provider from Javassist to ByteBuddy. Could you also confirm which one you’re using, and ideally compare them?

Use either:

hibernate.bytecode.provider=javassist

or:

hibernate.bytecode.provider=bytebuddy

Thanks!


#10

Hello,

I have this problem with both bytecode providers. I first tried with version 5.3.0.CR1 which as far as I know, was using javassist as the default bytecode provider. Now I’ve tried with 5.3.0.CR2 which is using byte buddy as default one and I have exactly the same behavior…

Taking into account such heap differences between fetch styles, I would like to know which are your recommendations in this regard.

  • How the three different styles (legacy, padded and dynamic) impact at database and java level?
  • Do you have any benchmark that could help me to choose the most suitable style for my model?

#11

Hi @caristu ,

Any chance you could share your memory dumps privately with us if they don’t contain any sensitive information?

In any case, it would be helpful if you could put together a test case reproducing your issue using our test case template: https://github.com/hibernate/hibernate-test-case-templates/tree/master/orm/hibernate-orm-5 .

It definitely looks like something we should fix so the sooner we have more information about the issue, the better.

Thanks!


#12

Hello,

yes I can share the dumps without trouble. How can I send them to you?

Besides, I would like to share with you the following changeset[1], for your consideration. It helped us to reduce the heap when using Hibernate 3.6. But it seems to be not enough after the upgrade to Hibernate 5.3.

[1] https://github.com/alostale/hibernate-orm/commit/612675c92c97bacd61d0c07a0802344eca42f5c0


#13

I shared a Google Drive folder with you. Hope it will work :).

Thanks!


#14

It worked :). Dumps uploaded into the folder:

  • hb36.hprof: the memory dump having Hibernate 3.6 (patched with the changeset mentioned in my previous post)
  • hb53cr2.hprof: the memory dump having Hibernate 5.3.0.CR2

Thanks!


#15

I studied the dump yesterday.

For now, your best bet is probably to use a dynamic strategy, even if it will slow things down a bit.

We are investigating possible ways of improving the situation, we will keep you in the loop.

If you have some time, any chance you could use our test case template (https://github.com/hibernate/hibernate-test-case-templates/tree/master/orm/hibernate-orm-5) to provide a reproducible test case.

The idea would be to import in the test case all the model related to the entity FinancialMgmtAccountingCombination (i.e. this particular entity and all its relations). Not sure how much work it would be but that would be very helpful for us to play with your case and see how we can improve things with a real use case in mind.

Thanks!


#16

Hello,

ok, I would appreciate if you could keep me in touch about your progress in this situation.

Regarding your suggestion about using the dynamic strategy, have you measured/compared the differences when switching between the strategies?

It would be great if you could share any kind of benchmark (in case you have) that could help us to determine how this slow down can impact us. Do you also know how this change can affect us in terms of garbage collection?

I’ll try to extract that part of the model to be able to send you a test case, but it can take me some time.

Finally, have you been able to check the changeset I provide in my previous response? Do you think if it could make sense to include it in Hibernate?

Thank you!


#17

Regarding your suggestion about using the dynamic strategy, have you measured/compared the differences when switching between the strategies?

Not really. What you can also do is reducing the batch size to something like 5. It should reduce by ~ a third the number of EntityLoaders per LegacyBatchingEntityLoader and it should help.

For now, I have identified the EntityLoaders as the culprit.


#18

Hello,

I’ve tried with 5 as DEFAULT_BATCH_FETCH_SIZE, and the retained heap is indeed reduced to 392 MB. In our case this is still 100 MB higher than before.

I’ve uploaded the memory dump (batchreduced.tar.gz) into the Google Drive folder, just in case you want to take a look.

Thanks!


#19

Yeah sure, it will be higher than before as you still have EntityLoaders created but far less than before.

I think it might be a good trade-off for you for the time being.


#20

I insist a bit because that would be really helpful to improve the situation. I saw you work at OpenBravo so I thought maybe I could get the sources and do the work myself but the sources I found seem to be very old and I couldn’t find the files by browsing the Mercurial UI (I haven’t checked out the repo though).