COM Object Lifetime in JACOB

introduction

JACOB Version 1.7 implements a new Threading Model that is more compatible with COM apartments. There is also an incompatibility between the Java object lifetime model and that of COM objects. COM Objects live and die by their reference count, whereas Java objects are collected by the Garbage Collector (GC) based on algortihms that are hidden from the user.

COM Object Lifetime in JACOB Prior to Version 1.7

In version 1.6 and earlier, JACOB objects which wrapped COM objects had finalize() methods that would call a native release method which would call a COM Release.

This has many problems. For one thing, the GC may take a long time to kick in and resource consumption may grow. However, the more problematic issue is that finalizers are called from a separate thread, and, as was discussed in the Threading Model document, this can result in COM errors if the object is running in an STA. Even if the object is running in an MTA, the finalizer may decide to run after we have terminated the thread that holds the component, in which case we would get fatal errors and crashes.

COM Object Lifetime in JACOB in Version 1.7

In Version 1.7, all JACOB objects which wrap COM objects extend com.jacob.com.JacobObject. This object has some special code to register itself with a com.jacob.com.ROT object which represents a Running Object Table (ROT). This table maps a Thread to the set of JacobObjects created in that thread. Therefore, when you call ComThread.Release(), the ROT checks whether that thread has created any objects, and these objects are released by calling their native release method (which is public).

This lifetime management method ties the lifecycle to the thread's lifecycle rather than the GC. The JacobObject's still have finalizers, but they will typically not perform the native release since that has already been called. The native release methods were written such that you can call them multiple times without worrying - since they zero out the native pointer when called the first time.

If you choose to call release methods on your objects yourself, that is allowed. In that case, when the thread is released the release calls will be no-ops.

It becomes important for you to call ComThread.Release() on any thread before you allow it to exit, otherwise you may get some random crashes later on in your code.