0

I'm using webServiceTemplate in my multithread Spring app. There are my jaxb dependencies:

compile('javax.xml.bind:jaxb-api:2.3.0')
compile('org.glassfish.jaxb:jaxb-runtime:2.3.0')

My application makes a lot esb requests and how I have noticed for each request/response (marshalSendAndReceive) jaxb creates an instance of UnmarshallerImpl which implements finalize() method and this is the problem for me, because objects creates faster than Finalizer thread can handle this objects, so it leads to memory leak. I'm wondering why do glassfish implementation still has finalize() in UnmarshallerImpl, it really creates problems for me. Is there any alternative versions of glassfish jaxb implementation or similar libraries? I will be grateful for any useful information.

UPD: I have also tried version 3.0.2 of jaxb:jaxb-runtime - the problem is still present

SorryForAsking
  • 323
  • 2
  • 18
  • Finalize() can not reliably be used for clean up. Sorry. You need to find a way to clean up manually – Just another Java programmer Apr 18 '22 at 16:06
  • Why do you text "glassfish developers still using" while your dependecy version is 2.3.0 which since 2017? Try to update your version and make sure that new version of this lib don't use finalize() – Dmitrii B Apr 18 '22 at 16:22
  • @Dmitrii I have tried version 3.0.2 before asking the question. This problem is still present in new version – SorryForAsking Apr 18 '22 at 16:37
  • What version of java are you using? Can you update jaxb-api to version 2.3.1? Also can you use version 2.3.6 of jaxb-runtime ? – pringi Apr 21 '22 at 09:32
  • Java 11. I can try versions that you suggested, but I have already tried higher version of jaxb, but it didn't help – SorryForAsking Apr 21 '22 at 12:57
  • If you have troubles with heap, maybe you should switch from JAXB to some streaming processing like StAX? – cyberbrain Apr 24 '22 at 10:26

2 Answers2

3

I think your best bet in the long term is to switch to processing your requests using an XML streaming implementation.

In the short term ...

  • As you noted, the JAXB reference implementation still uses finalize() in the latest release.
  • I don't think there is a way to increase the number of GC finalizer threads. (That is probably a good thing ....)
  • This Q&A lists some alternative JAXB implementation: List of JAXB providers
  • Since it is open source, you could modify the finalize() implementation for the UnmarshallerImpl you are currently using.

The standard implementation of the finalize() method looks like this:

@Override
@SuppressWarnings("FinalizeDeclaration")
protected void finalize() throws Throwable {
    try {
        ClassFactory.cleanCache();
    } finally {
        super.finalize();
    }
}

Thinking about it ... you may be able to get away with not cleaning the ClassFactory cache every time an UnmarshallerImpl instance is garbage collected. Maybe this could just set a "global" flag to tell an asynchronous cache cleaner that there is work to do.

Of course, there is a maintenance overhead in using a modified library in the longer term, so it would be advisable to try to get your changes accepted by the upstream project.

UPDATE

I should have looked at cleanCache earlier, but it appears that all it does is to drop a map that has been cached in a thread-local. This should be cheap, and shouldn't be a source of contention. Also, it means that doing this asynchronously (i.e. on a different thread!) won't be effective. (It also means that the Cleaner approach suggested below won't work either.)

The other alternative is to not to call cleanCache at all, but that gives us a potential memory leak via the thread local!!

Either way, I am (now!) puzzled that this finalize() method is a bottleneck at all. Are you sure that the problem isn't caused by a different one?


I'm wondering why do glassfish implementation still has finalize() in UnmarshallerImpl, it really creates problems for me.

The answer is obvious. They haven't gotten around to1 fixing it yet.


1 - Rhetorical questions: 1) How much money are you paying for support for your GlassFish implementation? 2) There are things called "open source bounties". Have you tried offering one to get this problem fixed?

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • The finalizer looks like it could be easily implemented with a [`Cleaner`](https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/lang/ref/Cleaner.html). Simply call `CLEANER.register(this, ClassFactory::cleanCache)` in the constructor. – Johannes Kuhn Apr 25 '22 at 00:12
  • 1
    @JohannesKuhn - True. But it strikes me that if the finalizer is being gummed up with this work, then it is likely to be expensive and/or subject to contention. Just using a `Cleaner` doesn't address that. It just pushes the problem somewhere else. Admittedly ... I don't have hard evidence that `cleanCache` is expensive or subject to contention. – Stephen C Apr 25 '22 at 00:18
  • 1
    The other thing is that `Cleaner` is only available on Java 9 and later, and the official JAXB-ri code needs to work on older versions. (And we don't know what the OP is running ...) – Stephen C Apr 25 '22 at 00:22
0

The finalize() method is currently deprecated, because it didn’t work as it supposed to. You have to use methods like System.gc() to finalize classes or else it wouldn’t work.

Discussion: Why is the finalize() method deprecated in Java 9?

acrastt
  • 104
  • 1
  • 7