finalize() not guaranteed to be called -- ever

T

Thomas Hawtin

Andrea said:
but, if you exit the program "cleanly" (that is, without calling
exit()), shouldn't the finalizers be called after all the threads are
terminated?

If all the threads have terminated, there is no thread to run the
finalisers in.

More to the point, the JVM automatically starts its shutdown sequence
when all *non-daemon* threads have terminated. Daemon threads will still
be running.

System.exit(0) is a completely normal way to exit. There's been enough
bugs that leave a non-daemon thread around to avoid leaving it to the
thread test.

Tom Hawtin
 
A

Andrea Desole

Thomas said:
If all the threads have terminated, there is no thread to run the
finalisers in.

More to the point, the JVM automatically starts its shutdown sequence
when all *non-daemon* threads have terminated. Daemon threads will still
be running.

yes, sorry, you are right. That's basically what I meant

System.exit(0) is a completely normal way to exit. There's been enough
bugs that leave a non-daemon thread around to avoid leaving it to the
thread test.

yes, it's probably not really safe.
I don't really like System.exit; it looks more like forcing the
application to exit abruptly. But it's just my opinion
 
P

Paul J. Lucas

Thomas Hawtin said:
Then the Java object should have some kind of dispose method.

I.e., a destructor... that you have to remember to call
manually.

IMHO, Java finalizers are broken. They *should* *always* be
called, and called immediately when their objects are no longer
reachable.

- Paul
 
P

Paul J. Lucas

Andrea Desole said:
But, if you are just looking for a clean solution to free your resources
when the application terminates, I think Ingo gave you a good answer.

No, I'm not.

- Paul
 
P

Paul J. Lucas

Thomas Hawtin said:
Two reasons spring to mind:
o Finalisers can be dependent upon other threads.

So just specify clearer rules for writing finializers so you
don't get yourself into trouble.
o Threads aren't killed until the plug is pulled on the JVM.

That *could* be different.
If you kill a thread that holds locks then you are in trouble. See
Thread.kill.

They *must* be killed anyway.

- Paul
 
T

Thomas Hawtin

Paul said:
IMHO, Java finalizers are broken. They *should* *always* be
called, and called immediately when their objects are no longer
reachable.

And you think that is in some way feasible?

Tom Hawtin
 
T

Thomas Hawtin

Paul said:
So just specify clearer rules for writing finializers so you
don't get yourself into trouble.

You don't think that finalisers are difficult enough to write as it is?
That *could* be different.

You could kill off threads, but then that causes the same problems as
using Thread.kill. It is deprecated with good reason.
They *must* be killed anyway.

Altogether, together with all objects. If you killed the objects too,
then there would be nothing for finalisers to do.

Tom Hawtin
 
E

Eric Sosman

Paul said:
I.e., a destructor... that you have to remember to call
manually.

IMHO, Java finalizers are broken.

Others may agree with you, but I think you'll find two
diametrically opposed reasons for considering them "broken."
Some think they're broken because they aren't destructors;
others think they're broken because the language shouldn't
have them in the first place. (This latter is Thomas Hawtin's
position, slightly overstated for dramatic effect; I hope
he'll forgive me the exaggeration.)
They *should* *always* be
called, and called immediately when their objects are no longer
reachable.

"Immediately" would seem to imply a full garbage collection
after every block exit, and perhaps even after every assignment
to a previously-initialized reference variable. If you really
wanted "immediately" I think you'd have to give up on garbage
collection and use some kind of one-at-a-time dependency tracing,
which sounds like it would be awfully expensive (especially in
the context of a multi-threaded program).

In any case: "Should be" and "Is" are two rather different
notions. If you want to use Java you're going to have to learn
to cope with Java's "Is" or else you're unlikely to make much
progress with it -- if you write your code for the way Java
"Should be" and your code doesn't work, complaining that Java
isn't perfect won't get the bugs out. If Java's "Is" is just
too bitter a pill to swallow, you'll need to find another
language.
 
P

Paul J. Lucas

Thomas Hawtin said:
And you think that is in some way feasible?

Yes, I do. Never heard of reference-counting? You could add a
dash of that in with the current garbage collector to be able to
detect "islands" of non-reachable objects.

But even if it's not "immediately," "shortly thereafter" would
be good enough probably. If the GC continuously ran on its own
thread, why not?

- Paul
 
P

Paul J. Lucas

Thomas Hawtin said:
Paul J. Lucas wrote:
[Threads] *must* be killed anyway.

Altogether, together with all objects. If you killed the objects too,
then there would be nothing for finalisers to do.

1. Kill all threads except a finalizer thread. (Objects still
exist.)

2. Finalizer thread runs all finalizers for remaining objects.

3. There is no step 3.

- Paul
 
T

Thomas Hawtin

Paul said:
Thomas Hawtin said:
Paul J. Lucas wrote:
[Threads] *must* be killed anyway.

Altogether, together with all objects. If you killed the objects too,
then there would be nothing for finalisers to do.


1. Kill all threads except a finalizer thread. (Objects still
exist.)

That is really dangerous. Thread.stop has the problem that synchronised
objects may be in an inconsistent state (who writes exception safe code
all the time?). Killing threads outright will mean that some objects may
still be synchronised with no owner. That's bad.

Tom Hawtin
 
T

Thomas Hawtin

Paul said:
Yes, I do. Never heard of reference-counting? You could add a
dash of that in with the current garbage collector to be able to
detect "islands" of non-reachable objects.

Funnily enough I have heard of reference counting. As you point out, it
doesn't actually work by itself. You'd need all of a real garbage
collector to do it properly. And that, as now, wouldn't give you
immediate finalisation.

Then of course you need to add an extra field to all objects. More
importantly the performance hit of reference counting is horrendous. You
of course will be synchronising (or similar) to the object every time
you gain or lose a reference.


I'm curious to know what your background is. It seems C++, but then
you'd know that modern, thread-safe, C++ string implementation don't use
copy-on-write because of the reference counting issues.

Tom Hawtin
 
P

Paul J. Lucas

Thomas Hawtin said:
Paul J. Lucas wrote:

That is really dangerous. Thread.stop has the problem that synchronised
objects may be in an inconsistent state (who writes exception safe code
all the time?)

Then it's the user's problem, as it should be. I'd rather have
finalizers that are guaranteed to run and am willing to pay the
price of having to write correct code.

- Paul
 
T

Thomas Hawtin

Paul said:
Then it's the user's problem, as it should be. I'd rather have
finalizers that are guaranteed to run and am willing to pay the
price of having to write correct code.

Then you set yourself a nigh on impossible task.

For instance, IIRC, the widely praised ThreadLocal fails on these
standards. If Josh Bloch and Doug Lea can't manage it, what chance have
the rest of us?

If you wrote correct code, you wouldn't need finalisers anyway.


And that is just one of the problems.

Tom Hawtin
 
D

Dale King

Paul said:
I.e., a destructor... that you have to remember to call
manually.

Which is not really that different from C++. C++ destructors are invoked
manually as well by calling delete.

I like to explain the difference between C++ and Java this way. There
are basically 3 parts of the end of the lifecycle of an object:

1. Releasing of non-memory resources
2. Freeing of the object's memory
3. Elimination of the last reference to an object.

The C++ model says that 1 & 2 occur at the same time when explicitly
commanded by the program through a delete statment. Number 3 may occur
sometime later, but will never occur before 1 & 2. This of course leads
to dangling pointers.

Java says that 2 will never occur before 3. There can never be a
dangling pointer. It places no restriction on when 1 occurs. The correct
way to do it is to have an explicit function that does #1. But through
the finalize method you can also do it when #2 occurs if you haven't
done it already.

Now one other difference between the 2 is that C++ allows objects to be
on the stack which will cause number 2 to occur without an explicit
delete call when the object goes out of scope. Of course, 2 can still
occur before 3. This can be used to free resources somewhat
automatically in C++ using an auto_ptr. Java puts all objects on the
heap, so objects never have a scope. The way to make sure something gets
cleaned up at the end of a scope in Java is to use a try-finally block.
It is a little more manual, but since Java only needs to do this for
non-memory resources it is not that common and generally only needs to
occur for files, DB connections, etc. In C++ you have to make sure that
memory resources are cleaned up yourself so you have to be more diligent
in using auto_ptr or explicit delete calls.

So from the perspective of the user of a class there is little difference:
- In C++ you do a delete to make sure that the resource is freed, in
Java you call a method on the object.
- You can still have a reference to the object afterward. In Java that
object will still exist so any attempts to use the object can be handled
safely. In C++ you are using a dangling pointer and can crash or destroy
data.
- C++ has an auto_ptr that can be used in some situations to free the
resources implicitly. Java has finally blocks that can be used to be
sure that the clean-up method is called explicitly. The finally block
only needs to be used when non-memory resources are concerned. In C++
you have to use the auto_ptr or some other mechanism for all resources
including memory. Also the C++ auto_ptr does not solve all problems. For
instance it doesn't work for multiple references to the same resource.
- In C++ if you don't explictly or implicitly free the resources they
will not be freed. With Java you have a safety net in the garbage
collector and the finalize method which can be used to free resources if
they haven't already been freed. It is not guaranteed to ever occur, but
some safety net is better than no safety net.
 
D

Dale King

Andrea said:
yes, it's probably not really safe.
I don't really like System.exit; it looks more like forcing the
application to exit abruptly. But it's just my opinion

And that is not the correct way to look at it. In languages like C/C++
you exit by returning from main and that is how you return an exit
status. The problem is however that C/C++ are single threaded languages.
The language itself does not support multiple threads. When you add
support for multiple threads the idea of basing things on returning from
main is completely unworkable. You have to allow any thread to be the
one to force an exit and return an exit status. You can't limit it
solely to the one thread that happened to call main.
 
R

Roedy Green

Java puts all objects on the
heap, so objects never have a scope.

The Jet compiler puts some objects on the stack so they automatically
are gced when they go out of scope. The JVM has so such provision,
but the language itself is flexible enough to accommodate it.

Conceptually, such a thing does not exist in Java even if it does in
practice as an optimisation.
 
A

Andrea Desole

Dale said:
And that is not the correct way to look at it. In languages like C/C++
you exit by returning from main and that is how you return an exit
status. The problem is however that C/C++ are single threaded languages.
The language itself does not support multiple threads. When you add
support for multiple threads the idea of basing things on returning from
main is completely unworkable. You have to allow any thread to be the
one to force an exit and return an exit status. You can't limit it
solely to the one thread that happened to call main.

that's not what I meant. I'm not talking about the thread calling main,
I'm talking about all threads. I prefer to avoid exit, let the threads
terminate "normally", and when the last thread terminates (which doesn't
have to be main) the virtual machine exits.
Maybe I can imgine that with many threads it might be easier to call
exit, but I usually don't use more than 2-3 threads (if I use more than
1, which is the most frequent case), and I prefer them to terminate by
following the regular flow of the code.
 
C

Chris Uppal

Andrea said:
that's not what I meant. I'm not talking about the thread calling main,
I'm talking about all threads. I prefer to avoid exit

I agree. By definition most code in a Java application is library code (if the
code is any good, it consists of lots of largely context-independent objects
that neither know nor care much about "applications"), so there are few places
where you legitimately /can/ call exit. The code that /might/ call exit
doesn't know enough about its context to tell whether it /should/ call exit,
simply because it doesn't know much about its context.

That doesn't mean that you should avoid exit altogether, but that the places it
is used should be very tightly controlled, and be part of the explicit
framework of the application, rather than scattered around. So it doesn't
really matter that Java is multi-threaded and C++ single-threaded; the
important point is that in both cases something that "knows about" the
application (and which is therefore almost inevitable closely associated with
the main() entry-point) has the job of deciding when/whether to clean-up and
die. No one else (threads, etc) have that right.

-- chris
 

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

Forum statistics

Threads
473,754
Messages
2,569,525
Members
44,997
Latest member
mileyka

Latest Threads

Top