Thread syncronization / finalization problem

M

mtp

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?
 
R

Robert Klemme

mtp said:
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?

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
 
P

Patricia Shanahan

Robert said:
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.

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
 
R

Remon van Vliet

Robert Klemme said:
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

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
 
J

John A. Bailo

Robert said:
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.
 
J

John A. Bailo

Robert said:
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.
 
R

Remon van Vliet

John A. Bailo said:
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.
 
M

mtp

Robert Klemme a écrit :
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.
 
R

Robert Klemme

mtp said:
Robert Klemme a écrit :

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;
}
}
}

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
}



i can't distribute information

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
 
M

mtp

Robert Klemme a écrit :
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.

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
 
C

Chris Uppal

Robert said:
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
 
R

Robert Klemme

Chris said:
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).

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top