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

Performance issue caused by the WeakReference in AbstractJaxbProvider #5843

Open
seaswalker opened this issue Jan 22, 2025 · 1 comment
Open

Comments

@seaswalker
Copy link

seaswalker commented Jan 22, 2025

final WeakReference<JAXBContext> ref = jaxbContexts.get(type);

Hi everyone!

Since we're using a weak reference here instead of a strong reference, once a GC happens, it will cause the JAXBContext to be reinitialized, which is a pretty expensive operation.

In our service, by using a custom JaxbContextResolver, we managed to reduce the response time by about 100ms (P90). So, should we provide an option here to let users decide whether to use strong or weak references?(Or an LRU cache with a size limit) I understand that the purpose of using weak references might be to reduce memory usage, but in reality, many services are more sensitive to response time.

@Provider
public class JaxbContextResolver implements ContextResolver<JAXBContext> {

  private final Map<Class<?>, JAXBContext> contexts = new HashMap<>();
  private final Lock lock = new ReentrantLock();

  @Override
  public JAXBContext getContext(Class<?> type) {
    JAXBContext context;
    lock.lock();
    try {
      context = contexts.get(type);
      if (context == null) {
        context = JAXBContext.newInstance(type);
        contexts.put(type, context);
      }
    } catch (JAXBException ex) {
      throw new RuntimeException(ex);
    } finally {
      lock.unlock();
    }
    return context;
  }
}
@jbescos
Copy link
Member

jbescos commented Jan 28, 2025

Try this other, it should be even faster:

@Provider
public class JaxbContextResolver implements ContextResolver<JAXBContext> {

  private final ConcurrentHashMap<Class<?>, JAXBContext> contexts = new ConcurrentHashMap<>();

  @Override
  public JAXBContext getContext(Class<?> type) {
    return contexts.computeIfAbsent(type, t -> {
      try {
        return JAXBContext.newInstance(t);
      } catch (JAXBException ex) {
        throw new RuntimeException(ex);
      }
    });
  }
}

Regarding your question, I'd prefer to set a limit of size in the map.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants