Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / May 2006

Tip: Looking for answers? Try searching our database.

Thread syncronization / finalization problem

Thread view: 
mtp - 09 May 2006 16:25 GMT
Hello,

i think i've found an unsolvable problem :(

Let's say i have a class "VeryComplexObject". In one of the method
(which is synchronized) i call in a catch handler
System.runFinalization() because i need to recover resources.

The problem is, several "PrettySimpleObject" get finalized, and in its
finalizer, it must remove some data in "VeryComplexObject", which is locked.

And by the way, at the same time, the EDT is reading data from
"VeryComplexObject" to show them (the read methods of
"VeryComplexObject" are not synchronized).

Have you any idea how to solve this problem?
Robert Klemme - 09 May 2006 16:34 GMT
> Hello,
>
[quoted text clipped - 13 lines]
>
> Have you any idea how to solve this problem?

Your architecture seems rather contrived.  Don't explicitly invoke
finalization.

Redesign your classes to better distribute information among classes and
also obviate the need for resource deallocation via finalizers.  For
example you can use try {} finally {} to enforce cleanup code.  If it's
complex you can still use the command pattern, i.e. create a class for
your complex operation and give it a method that does all the cleanup
stuff; then call this method from a finally block.

Regards

    robert
Patricia Shanahan - 09 May 2006 17:07 GMT
>> Hello,
>>
[quoted text clipped - 23 lines]
> your complex operation and give it a method that does all the cleanup
> stuff; then call this method from a finally block.

There is an alternative in the current structure: Give each
VeryComplexObject a resource recovery queue, and a resource recovery
thread dedicated to removing items from the queue and executing them.
The finalizer would construct and queue up a resource recovery request,
but not try to do any recovery itself.

However, this would make VeryComplexObject even more complex, which does
not seem like a good idea. I think some refactoring with the aim of
making this easier would be a better plan.

Patricia
Remon van Vliet - 09 May 2006 17:13 GMT
>> Hello,
>>
[quoted text clipped - 27 lines]
>
> robert

First of all, everything robert said is perfectly valid.

Now, calling runFinalization() does nothing more than hint the JVM to put
more effort into calling the finalize() method of objects pending removal
(in other words, objects that the GC will clean up at some point in the
future). Basically, unless you have a really good reason (and i cant really
think of one), dont touch that method.

Secondly, it's a bad idea to do anything in any finalize() method that can
potentially block. For example, instead of removing something from your
complex object in the finalize() method you could start a seperate thread
that does the removing instead (obviously you must not pass a reference to
the object being finalised to that thread or you'd be ressurecting your
simple object).

Finally, counting on finalizers to do anything but clean up native resources
or implement some sort of object reuse scheme is probably bad design, so i
strongly suggest you reconsider your options and look for a more clean
approach. Perhaps if you give some additional info i can suggest
alternatives. Good luck.

- Remon van Vliet
John A. Bailo - 09 May 2006 17:40 GMT
> Your architecture seems rather contrived.  Don't explicitly invoke
> finalization.

I don't think it's contrived at all, but very typical.

Instead of "complex object", "simple object", think server and client.

In the case where serveral client objects are consuming resources on the
server object, and you want to dismiss the server object, while at the
same time not hanging the clients -- but notifying them that "hey, the
server just went away, so when you need to close, just go ahead".

This would suggest to me just such an arrangement, where a closing /Very
ComplexObject/ needs to notify all "SimpleObjects" that consume it, that
it is going away.

Alternatively, in the finally() clause where you would try and "remove
some data" there would be another try/catch, that would catch an
exception if VeryComplexObject no longer exists, and then continue on to
finalize SimpleObject.
Remon van Vliet - 09 May 2006 19:22 GMT
>> Your architecture seems rather contrived.  Don't explicitly invoke
>> finalization.
>
> I don't think it's contrived at all, but very typical.

I think he was referring to using finalizers for this that that makes the
architecture contrived. A point with which i agree, but perhaps i
misunderstood.
John A. Bailo - 09 May 2006 17:40 GMT
> Your architecture seems rather contrived.  Don't explicitly invoke
> finalization.

I don't think it's contrived at all, but very typical.

Instead of "complex object", "simple object", think server and client.

In the case where serveral client objects are consuming resources on the
server object, and you want to dismiss the server object, while at the
same time not hanging the clients -- but notifying them that "hey, the
server just went away, so when you need to close, just go ahead".

This would suggest to me just such an arrangement, where a closing /Very
ComplexObject/ needs to notify all "SimpleObjects" that consume it, that
it is going away.

Alternatively, in the finally() clause where you would try and "remove
some data" there would be another try/catch, that would catch an
exception if VeryComplexObject no longer exists, and then continue on to
finalize SimpleObject.
mtp - 10 May 2006 08:55 GMT
Robert Klemme a écrit :

>> Hello,
>>
[quoted text clipped - 16 lines]
> Your architecture seems rather contrived.  Don't explicitly invoke
> finalization.

i need to. I'm using MappedByteBuffer, which don't have an unmap method,
and which are limited (in number * size). So i need them to be freed
before being able to allocate new ones. The code looks like this:

while (!success && tries < maxTries) {
  try {
    MappedByteBuffer buffer = fc.map(...);
    success = true;
  } catch (IOException ex) {
    boolean noMoreMem = ex.getMessage().equals("Cannot allocate memory");

    if (noMoreMem) {
      System.gc();
      System.runFinalization();

      tries++;
    } else {
      throw ex;
    }
  }
}

if (tries >= maxTries) {
  // fatal error
}

> Redesign your classes to better distribute information among classes and
> also obviate the need for resource deallocation via finalizers.  For
> example you can use try {} finally {} to enforce cleanup code.  If it's
> complex you can still use the command pattern, i.e. create a class for
> your complex operation and give it a method that does all the cleanup
> stuff; then call this method from a finally block.

i can't distribute information

the "delaying cleanup" idea is pretty good. I think i will use the
"resource recovery queue" of Patricia.

Remon:

starting another thread might be the solution. The thread will wait
without problem the lock release.

I didn't choose the design of the the app, i'm an employee. Sorry but i
can't rewrite everything from scratch. I have to use it like this.

Thx to you all for your apreciated help.
Robert Klemme - 10 May 2006 09:42 GMT
> Robert Klemme a écrit :
>>
[quoted text clipped - 40 lines]
>   }
> }

IMHO this won't work.  If you get an OutOfMemory error (even disguised
as an IOEx) you cannot free any more memory by doing System.gc() because
the JVM *must* GC before it is allowed to throw this exception.  Also
System.gc() does neither guarantee that GC is run immediately nor that
it has finished once the method returned.

> if (tries >= maxTries) {
>   // fatal error
[quoted text clipped - 11 lines]
> the "delaying cleanup" idea is pretty good. I think i will use the
> "resource recovery queue" of Patricia.

Better than a non working solution.

> I didn't choose the design of the the app, i'm an employee. Sorry but i
> can't rewrite everything from scratch. I have to use it like this.

I'm sorry for you.  That's not fun.

> Thx to you all for your apreciated help.

You're welcome.

Kind regards

    robert
mtp - 10 May 2006 10:06 GMT
Robert Klemme a écrit :

>> Robert Klemme a écrit :
>>
[quoted text clipped - 46 lines]
> System.gc() does neither guarantee that GC is run immediately nor that
> it has finished once the method returned.

From what i've read, the IOException does not come from no more java
memory, but from no more "adressable space" (a monitoring of
Runtime.getRuntime().freeMemory() shows that).

It's true that i've also seen some people saying that a
Thread.sleep(some) was helping. I will add it, to let more time for the
gc to finish.

Even if this is not perfect, at this point, i have 2 choice: fatal error
(restart of application needed) or make it work. So even if i use some
hack or undocumented feature, or "do-not-always-work" feature, it's not
an important issue.

Best regards
Chris Uppal - 10 May 2006 11:45 GMT
> IMHO this won't work.  If you get an OutOfMemory error (even disguised
> as an IOEx) you cannot free any more memory by doing System.gc() because
> the JVM *must* GC before it is allowed to throw this exception.

I'm not absolutely sure, but I don't think that's true in this specific case.
If the attempt to create a MappedByteBuffer fails (at the OS level) then that
doesn't trigger GC first (since the memory in question is not GCed).

   -- chris
Robert Klemme - 10 May 2006 12:39 GMT
>> IMHO this won't work.  If you get an OutOfMemory error (even disguised
>> as an IOEx) you cannot free any more memory by doing System.gc() because
[quoted text clipped - 3 lines]
> If the attempt to create a MappedByteBuffer fails (at the OS level) then that
> doesn't trigger GC first (since the memory in question is not GCed).

Yeah, I wasn't sure 100% myself that's why I wrote "IMHO".  Could well
be that you're right.  Still this hack leaves an awkward feeling with
me.  If was in his position I'd at least investigate a bit to see
whether I can improve the overall design.  Even if I detect it's too
much effort or not doable because of other constraints I could at least
write it down and use that for documentation or suggestions for improvement.

Btw, using SoftReference to those buffers might or might not be a fairly
easy change that would make up for (semi) automatic collection of the
memory.  But as I said, I'd prefer explicit cleanup...

Cheers

    robert


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.