vtkJavaMemoryManager issue

Hello,

maybe I am missing something but it seems to me that there is an issue in the vtkJavaMemoryManagerImpl class. Let me describe the scenario:

I am overriding in my Java code the vtkPolygonalHandleRepresentation3D to add some special behavior:

public class HandleEntityRepresentation extends vtkPolygonalHandleRepresentation3D {
...
}

Then I assign the representation to a widget:

vtkHandleWidget widget;
HandleEntityRepresentation representation;
widget.SetRepresentation(representation);

The crucial point here is that I do not store the reference to representation anywhere in my Java code (local variable only) and fully rely on the vtkHandleWidget.GetHandleRepresentation() assuming that I can get my HandleEntityRepresentation back by the call:

(HandleEntityRepresentation) widget.GetHandleRepresentation();

The problem is that sometimes this call ends with the ClassCastException:

java.lang.ClassCastException: class vtk.vtkPolygonalHandleRepresentation3D cannot be cast to class cz.gsl.gfm.cad.gui.vtk.entity.HandleEntityRepresentation

So first of all I verified, that I have not called the widget.SetRepresentation(representation) with a vtk.vtkPolygonalHandleRepresentation3D and I am pretty sure that it is not happening.

Then I started to investigate how the widget.GetHandleRepresentation() works and get to the vtkJavaMemoryManagerImpl class. In my opinion the reason of issue I am facing is the

private HashMap<Long, WeakReference<vtkObjectBase>> objectMap;

containing the WeakReference instances as values. In my case the reference to the representation is not stored anywhere in Java code so GC can assume the referent of its WeakReference record in objectMap can be finalized. When

public vtkObjectBase getJavaObject(Long vtkId)

is called value from the objectMap will contain WeakReference with a null and because of that following condition is true:

    // We need to do the work of the gc
    if (value != null && resultObject == null) {
      this.unRegisterJavaObject(vtkId);
    }

Finally the record is recreated by the following:

    // No-one did create it, so let's do it
    if (resultObject == null) {
      try {
        String className = vtkObjectBase.VTKGetClassNameFromReference(vtkId.longValue());
        Class<?> c = Class.forName("vtk." + className);
        Constructor<?> cons = c.getConstructor(new Class<?>[] { long.class });
        resultObject = (vtkObjectBase) cons.newInstance(new Object[] { vtkId });
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

But as a native vtk class instance and so the ClassCastException is thrown.

To avoid such behavior I had to introduce a property

private HandleEntityRepresentation representation;

to my HandleEntityWidget class and method

public void SetRepresentation(final HandleEntityRepresentation representation) {
    super.SetRepresentation(representation);
    this.representation = representation;
}

to store my representation instance there to prevent the GC to finalize it.

It is a valid solution but was quite difficult to find out what is going on here. So I would suggest to change the vtkJavaMemoryManagerImpl implementation somehow to avoid this kind of issues. I fully understand the reasons why WeakReference is used there but this side effect I am struggling with is unpleasant.

Petr

I guess the main assumption I made when I wrote that class was that any code extension will be done on the C++ side and Python or Java will just make use of it. I don’t think we intended to be able to override any class in any wrapped langage and allow it to work. For such use case, we have special case such as ProgrammableSource/Filter that allow to have some core algo written in a different langage but ultimately the container object is indeed a C++ class.

Do you have a suggestion on how to better solve your problem?

The descendant class, HandleEntityRepresentation, is a red herring.

Every Java object you create must be held separately as a strong reference to keep it alive, no matter how it is used elsewhere in the wrapper code. So rather than changing HandleEntityRepresentation.SetRepresentation(), I would hold onto the representation in the Java code where it is created or simply put it into a list. Then clear the reference or list when the operation is finished.

Hello Sebastien,

thank you for yor reply. I have already been thinking about my suggestions during my original post writing but nothing simple and elegant enough come to my mind unfortunately.

To support my use case you definitely have to remove the WeakReference but this will lead to memory leaks at the vtkJavaMemoryManager that will hold the references in its objectMap forever. To solve it vtkJavaMemoryManager should somehow listen/observe the vtkObjectBase destructor (no idea if possible?) and remove related record from the objectMap when notified. This seems to me safe enough (Can a Java instance exist without its C++ counterpart?) and at least in my case will work.

But what I would suggest definitely is to mention this limitation of the vtkJavaMemoryManager in the documentation (mainly The VTK User’s Guide chapter 18.6).

Hello Todd, what do you mean by “being a red herring”?

@cory.quammen can you make sure we keep that info in our VTK guide?

I’m not the keeper of the VTK Guide. Maybe @lorensen can add it?

@mat127 A red herring is a piece of misleading information. What I mean is that the problem exists regardless of whether or not vtkPolygonalHandleRepresentation3D is sub-classed.

You are absolutely right that a strong reference cannot be held by the memory manager unless the underlying C++ objects support a notification mechanism on destruction. So, in the absence of such an observer pattern in VTK, your only option is to hold onto the Java objects you create in your own code. This requirement is the same for c# and, I presume, Python wrapper code.