Introduction
Firstly, it is worth explaining the original intended purpose of the finalize
method within the Java specification. It is called implicitly by the Java Virtual Machine when it has determined all references to that specific object have left usable scope. To quote the specification...
Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the finalize method to dispose of system resources or to perform other cleanup.
More detail can be found here.
What did IBM MQ use the finalize
method for?
The IBM MQ Classes for JMS (Java Message Service) employed the finalize
method for cleanup of resources where appropriate, and most notably for cleanup of the JmqiWorkerThread
objects. These JmqiWorkerThread
objects are most commonly created when a BINDINGs connection is used, as opposed to TCP/IP. However, the JmqiWorkerThread
can also be employed, through use of specific Java system properties, when a TCP/IP connection is used. The worker threads are used for asynchronous MQ API work, such as MQCONN, MQGET etc.
Now, when a JMS Connection object is created, for example by calling MQQueueConnection.createConnection(...)
, a JmqiWorkerThread
object (and thread) would be spawned to service the MQAPI calls occurring on that Connection object (provided the aforementioned pre-requisites are met). Once the Connection object had gone out of "scope", i.e. the Java Garbage Collector had deemed no usable references remained, the finalize
method implementation would be called, resulting in the JmqiWorkerThread
objects being tidied (through use of join
etc). This in-turn would prevent any JmqiWorkerThread
objects from being leaked, which over the time-span of a long running application, would prevent significant heap usage and indeed potential OutOfMemory
exceptions.
Why did IBM MQ remove the finalize
functionality from their Java client offerings?
The reasoning for the removal and change in behaviour is two-fold...
- The Java specification have officially deprecated the
finalize
method since version 9.
- The IBM MQ Java client offerings moved towards Java 17 with the release of 9.2.4 CD (and hence 9.3 LTS) onwards.
As for point [1], here is the official Java specification reasoning for deprecation...
Deprecated.
Since a provider typically allocates significant resources outside the JVM on behalf of a connection, clients should close these resources when they are not needed. Relying on garbage collection to eventually reclaim these resources may not be timely enough.
More details can be found here.
So, how does this affect you and your client application(s)?
If you have IBM MQ Classes for JMS reliant client applications in your workload, utilising a version at or later than 9.2.4 CD, then you might experience increased heap usage and potential OutOfMemory
exceptions in the JVM. As explained above, this is potentially caused by an oversight in failing to call close
on JMS Connection objects before they go out of scope, ultimately resulting in leaked JmqiWorkerThread
objects.
The solution is to check your application code carefully, analysing all potential code paths, and ensuring that close
is always explicitly called, as per the JMS specification, on suitable JMS objects.