vendredi 17 mars 2017

Verify object deletion in Java

In my code there are many objects created and deleted during runtime which can have long reference chains (i.e. be reachable in terms of garbage collection from many places).

In my unit test I want to verify that when I "delete" an object, e.g. remove it from the list that primarily contains it, all references to that object are deleted. To be clear: I want to verify that no reference to this object exists anymore in my application.

How can I achieve this?

So far I came only up with this (testing that a PhantomReference is enqueued):

@Test
public void test_objectX_can_be_garbage_collected() throws Exception {

    ReferenceQueue<MyClass> refsToBeDeleted = new ReferenceQueue<>();
    MyClass obj = new MyClass();
    PhantomReference<MyClass> phantomRef = new PhantomReference<MyClass>(obj, refsToBeDeleted);

    obj = null;   // delete last strong reference to obj
    System.out.println("Reference is enqueued:" + phantomRef.isEnqueued()); // "false"

    System.gc();   // invoke garbage collection
    Thread.sleep(1000L);   // required - see text
    System.gc();   // invoke garbage collection again
    System.out.println("Reference is enqueued:" + phantomRef.isEnqueued()); // true
}

with

public static class MyClass {
}

The doc says:

public static void gc()

Runs the garbage collector. Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

(emphasis mine)

This is quite vague ("best effort") and seems quite non-deterministic, e.g. I have to either wait 1 second and call gc() again, or call it e.g. four times in a row for the reference to be enqueued.

Is there any way to do this properly? I want to test that objects don't persist and will eventually flood my memory after months of uptime.

Remarks:

1.) I know you should not call gc() because it's bad code. True, but I am calling it from test code to verify production code.

2.) I know that gc() is actually not deterministic from a local point of view. I'm aware of this and asking for a better alternative.

Aucun commentaire:

Enregistrer un commentaire