Reputation: 341
The following simple Jersey call is leaking Objects into the Finalizer queue:
public boolean startExperiment(Experiment experiment) { final Client client = ClientBuilder.newClient(); Response response = null; RunDescriptor runDescr = experiment.getRunDescriptor(); try { final WebTarget webTarget = client.target(ExperimentController.getInstance().getRunnerUrl()).path("runs").path("startNewAsyncrun"); response = webTarget.request().post(Entity.entity(runDescr, MediaType.APPLICATION_JSON)); if (response != null && response.getStatusInfo().getStatusCode() != Status.CREATED.getStatusCode()) { System.out.println("Error, Run not created! Response Info: " + response.getStatusInfo()); return false; } else { return true; } } finally { if(response != null) { response.close(); } client.close(); } }
Jersey versions with which I tested: 2.18, 2.20, 2.22.2, 2.23.1. The code is run from multiple threads (each thread running it once every minute, for example). Also closing Response and Client should not be necessary, added it jsut in case to test if it would help. Eclipse MAT shows Finalizer queue to be growing with Objects of type:
Any help or thoughts on the matter is really appreciated!
Upvotes: 0
Views: 1265
Reputation: 1
Was facing the same issue, Paul Samsotha's answer helped. Creating Client loads jersey jars and JARFile in java overrides finalize method putting lot of overhead on finalizer thread.
Upvotes: 0
Reputation: 6497
While I am not familiar with Eclipse MAT and what it is showing you, it is proper behavior for some objects to go through the Finalizer queue.
Under normal circumstances, any object that overrides the finalize
method will be queued for finalization (which consists of calling the finalize
method). The general idea is that when the garbage collector identifies an object as unreachable, it looks to see if the finalize
method is overridden and has not yet been called. If finalize
is defined and has not yet been called, then the object is queued for finalization, otherwise the memory is collected.
The finalizer appears to be implemented as a queue that is serviced by a single thread. The thread processes each object in the queue by calling finalize
. After the call to finalize
completes, the object is removed from the queue.
Subsequently, when the garbage collector again determines that the object is unreachable, it will find that finalize
is overridden, but has already been called. The member is collected.
Note that using this feature delays collection of garbage. And while it is a convenient way to clean up an object, the JVM does not guarantee when or even if the finalize
method will be called.
One related risk is "finalizer starvation." You mention "growing" so perhaps this is an issue you are facing. If you create enough garbage that requires finalization and if that finalization takes too long, you can actually run out of memory because the single finalizer queue cannot keep up. There are a number of ways to deal with this situation:
finalize
complete (infinite loops are bad) and quickly.finalize
.If you are seeing starvation, use a thread dump to see what the Finalizer thread is working on.
Upvotes: 1