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.