Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow clearing all caches to avoid classloader leaks #4953

Closed
jin-harmoney opened this issue Feb 6, 2025 · 3 comments
Closed

Allow clearing all caches to avoid classloader leaks #4953

jin-harmoney opened this issue Feb 6, 2025 · 3 comments
Labels
2.19 Issues planned at 2.19 or later
Milestone

Comments

@jin-harmoney
Copy link
Contributor

jin-harmoney commented Feb 6, 2025

Is your feature request related to a problem? Please describe.

I'm using both hypersistence-utils and jackson in my Quarkus project and I see that my application classloader is not garbage collected on live-reload.

This seems to be caused by the static ObjectMapper in ObjectMapperWrapper.

The ObjectMapper is not loaded by the application classloader, but it does contain references to classes of the my application (custom deserializers etc). Hence, it blocks the garbage collection of the application classloader.

I described a similar case for hibernate-envers here.

Describe the solution you'd like

As mentioned in another issue, a clear() method on ObjectMapper to evict all caches before the application shuts down would probably solve this.

Usage example

Specifically when using hypersistence-utils, it would be ObjectMapperWrapper.INSTANCE.getObjectMapper().clear();. That code would be placed in a method annotated with @Shutdown.

Additional context

No response

Workaround

// Hypersistence utils uses an object mapper. The object mapper has several caches that keep references to classes and cause classloader memory leaks.
var hyObjectmapper = ObjectMapperWrapper.INSTANCE.getObjectMapper();
hyObjectmapper.getTypeFactory().clearCache();

// mapper._rootDeserializers is private, so we need to clear it using reflection
var field = hyObjectmapper.getClass().getDeclaredField("_rootDeserializers");
field.setAccessible(true);
var rootDeserializers = (Map) field.get(hyObjectmapper);
rootDeserializers.clear();

// DeserializationContext._cache is private, so we need to clear it using reflection
field = hyObjectmapper.getDeserializationContext().getClass().getSuperclass().getSuperclass().getDeclaredField("_cache");
field.setAccessible(true);
var cache = (DeserializerCache) field.get(hyObjectmapper.getDeserializationContext());
cache.flushCachedDeserializers();

// Flush other stuff
((DefaultSerializerProvider) ObjectMapperWrapper.INSTANCE.getObjectMapper().getSerializerProvider()).flushCachedSerializers();
@jin-harmoney jin-harmoney added the to-evaluate Issue that has been received but not yet evaluated label Feb 6, 2025
@cowtowncoder cowtowncoder added the 2.19 Issues planned at 2.19 or later label Feb 6, 2025
@cowtowncoder
Copy link
Member

cowtowncoder commented Feb 6, 2025

Sounds like good idea. PR would be welcome (as usual, but might be easy enough to implement).

On naming, instead of clear() needs to be clearCaches() (or clearAllCaches()) but aside from that.

@cowtowncoder cowtowncoder added pr-welcome Issue for which progress most likely if someone submits a Pull Request and removed to-evaluate Issue that has been received but not yet evaluated labels Feb 6, 2025
@cowtowncoder
Copy link
Member

One other quick note: usually one should drop ObjectMapper instance to get rid of references. But in practice static instances are probably quite widely used so we can help such usage by adding this feature.

@cowtowncoder
Copy link
Member

Completed for 2.19(.0).

@cowtowncoder cowtowncoder removed the pr-welcome Issue for which progress most likely if someone submits a Pull Request label Feb 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.19 Issues planned at 2.19 or later
Projects
None yet
Development

No branches or pull requests

2 participants