DGC Behaving unexpectedly

I have an RMI application in which objects on the server are not being garbage collected as I have been led to believe should happen.

Generally speaking, the server consists of an instance of a 'factory' class [call it MyObjFactory] object that is bound to the Registry. The client creates instances of another Remote class [call it MyObj] through this 'factory'. The client uses the MyObj and then calls a free() method to indicate when it is finished with it, and then releases all references to the MyObj stub. The free() method triggers the server to call unexportObject() and release all references to the MyObj.

The application has been working for a year or more, but as demand increases, it has become apparent that memory usage is a problem. Using a heap analysis tool and verbose dgc, I have discovered that although the server has no strong references to the MyObj instances, they hang around indefinitely because the client continues to renew leases for them despite the fact that it has set all stub references = null!

In a test scenario I have my client locate the factory create 1000 MyObj instances and immediately free() them:

// in the MyObjImpl class:

public void free()

{

UnicastRemoteObject.unexportObject(this,true); // i know this is working because if the client

// tries to use the object afterwards, a

// NoSuchObjectException occurs

localFactory.removeMe(this); // destroys the ONLY server-side reference to this instance

}

// test loop on client:

MyObjFactory factory = registry.lookup("MyObjFactory");

for (int i = 1; i <= 1000; i++)

{

MyObj obj = factory.createNew();

obj.free();

obj = null;

}

After this finishes running, there are 0 (zero) instances of the stub remaining on the client side [as you would expect]. However, 1000 MyObjImpl instances continue to live on the server side,I have confirmed this through heap analysis.

Meanwhile dirty() calls continue to be received for these 1000 objects. I have confirmed this also by using sun.rmi.dgc.logLevel=VERBOSE and also by examining the lease expiry time which continues to be updated. Oh, and by the way, I set the leaseValue and checkInterval to 5000 ms to speed up the results of my test.

NOW THE INTERESTING PART: When i forcefully terminate the client, the leases eventually DO expire and the MyObjImpl instances are gc'd. So there are obviously some references to their stubs on the client - but they are definitely NOT strong references!

Can anyone suggest what more i can do to prevent the persistent lease renewals that are preventing these unused resources from being gc'd on the server side? I have read something about 'Phantom References' - could this be part of the problem? I don't even need the DGC because I feel I am managing object lifespan effectively myself. Is there any way to disable DGC and all of its leasing shinanigans?

[2996 byte] By [kevinkilmerchoia] at [2007-9-19]
# 1
Any luck with this? Please let me know if you have found the problem.Thanks.
alex_magurana at 2007-7-8 > top of java,Core,Core APIs...
# 2

if the remote objects are still on the heap then that is what is causing the DGC to continue leasing. Presumably if you run the local GC yourself using System.gc(), the objects will be reclaimed (since you have said there are no references to them) and the DGC will discontinue its maddening attempts to continue leasing. At least, that is the best quess i can come up with. give it a try and let me know if it works.

Alex

afield1a at 2007-7-8 > top of java,Core,Core APIs...
# 3
i re-read your post and now im not so sure about my reply. If you are sure that the stubs are no longer on the client side then i have no explanation at all for your problem.
afield1a at 2007-7-8 > top of java,Core,Core APIs...
# 4

I have a similar problem and I did a heap analisys as well.

What I found out is that the client side of the DCG is running on a separate thread and it maintains a list of remote stubs. So even if you remove all the references to a remote object in your code you still have references to those objects from that thread. This explains why if you kill your application the references on the server are finally released.

I still don't have a solution for that, but I hope that this information can help you.

Alex

alienistya at 2007-7-8 > top of java,Core,Core APIs...
# 5

> So even if you remove all the

> references to a remote object in your code you still

> have references to those objects from that thread.

But they are phantom references. The following is quoted without permission from a comment in sun.rmi.transportDGCClient:

* The DGCClient tracks the local reachability of registered LiveRef

* instances (using phantom references). When the LiveRef instance

* for a particular remote object becomes garbage collected locally,

* a "clean" call is made to the server-side distributed garbage

* collector, indicating that the server no longer needs to keep the

* remote object alive for this client.

So, provided that GC eventually reaps the strong references, the client-side DGC should release the stubs. There is no guarantee that this will ever happen. In practice I find that calling System.gc() occasionally doesn't hurt.

ejpa at 2007-7-8 > top of java,Core,Core APIs...