Hello,
last week, we upgraded a legacy web application to hibernate-core 5.5.7.Final and were affected by an OOM error which manifests exactly as described in HHH-14694: when an entity manager factory is closed, its ByteBuddy-synthesized proxy classes with names like com.example.Account$HibernateProxy$T803qhHQ remain in memory and exhaust the metaspace after some time.
Trying out different things with the test case which is attached to that Jira issue, using Javassist instead of ByteBuddy (-Dhibernate.bytecode.provider=javassist) solves the problem for us, but as Javassist is deprecated, I would like to ask if there is any other known workaround or whether the bug will be fixed some time soon.
I’m not aware of anyone actively working on this. Why do you create and close multiple entity manager factories though? This is not really a use case that we invest a lot of time into, although I agree that we should fix this issue eventually.
thank you for your quick reponse! As this is (legacy) code which we didn’t touch, I need to investigate a bit further on why multiple factories are instantiated.
We have the same problem in our professional context: a process runs out of meta space because of thousands of hibernate proxies.
The use-case is a data base export: we export application meta data into a SQL database. To this end, the entitymanagerfactory is instantiated temporarily.
A systematic solution would be highly appreciated, especially since support for javaassist has been marked as deprecated.
We also have the same problem. A user can define new properties and entity types at runtime, so we dynamically build a Hibernate configuration and session factory. Now we’re using ByteBuddy, we have a memory leak.
Did you try constructing your SessionFactory with a custom class loader to load entities in isolation yet? I didn’t dig into the topic that much, but I suspect a proxy class must use the same class loader as the class it extends, so isolating the entity classes in your case should do the trick.
I don’t think a custom class loader would help. That’s because, as you say the proxy class must be in the same class loader as its entity class, and so you can only garbage collect the proxy class if its class loader is garbage collected. That means you would need the entity classes to be eligible for garbage collection. That’s not something I can see working with my use case, and I don’t imagine it being common for others either.
What I have done is to try modifying SessionFactoryObserverForBytecodeEnhancer so that it never calls BytecodeProvider.resetCache(). When I did that, memory use dropped a lot, and the performance increased a lot too when creating a session factory after it’s already created one. That’s because it doesn’t try to generate a whole load of proxy classes due to the caching working.