Throwing Constructor Exceptions and cleaning up

R

Richard Maher

Hi,

If when an object's constructor throws an exception that object has not in
fact been intantiated, then what happens to the bits/objects/variables that
were initialized/instantiated before the exception was thrown?

For example, if I open a file, or connect a socket while constructing an
object and then throw an exception before the constructor/instantiation
completes, then what happens to the file or socket connections that were
successfully instantiated?

a) Garbage Collected in the fullness of time as they're no longer
referenced?
b) Destroyed, and o/ride finalize() method that's called immediately?
c) It's considered extremely bad form to do this in a constructor. Have an
init() method instead?
d) Make sure you close the file/Socket before throwing the execption
e) Something else. . .

I know there stuff on the web, and I am looking it up as we speak, but there
is rather a lot of stuff on Exceptions so if someone here can help me out
I'd really appreciate it.

Cheers Richard Maher
 
J

Joshua Cranmer

Richard said:
If when an object's constructor throws an exception that object has not in
fact been intantiated, then what happens to the bits/objects/variables that
were initialized/instantiated before the exception was thrown?

Java by default zero-initializes every single field in your class before
it gets around to invoking the constructor. Indeed, the JVM sees the
constructor as merely "just another method," albeit one with a funky name.
For example, if I open a file, or connect a socket while constructing an
object and then throw an exception before the constructor/instantiation
completes, then what happens to the file or socket connections that were
successfully instantiated?

The same things that happen when an exception abruptly terminates code
using file or socket connections in regular methods. The most correct
thing to do would be the try/finally idiom for streams.
a) Garbage Collected in the fullness of time as they're no longer
referenced?

All objects are GC'd once they lose all references (and the GC gets
around to collecting them). If they're local variables, they die when
the method loses scope; if they're instance variables, they die when the
instance loses references, which will likely be soon anyways.
b) Destroyed, and o/ride finalize() method that's called immediately?

finalize() is only called sometime after GC happens--an event that could
happen now or sometime next year. Or never, in some cases.
c) It's considered extremely bad form to do this in a constructor. Have an
init() method instead?

d) Make sure you close the file/Socket before throwing the execption

Well, this is good practice no matter what the circumstances.
 
L

Lew

Peter said:
There are too many examples of constructors that do throw exceptions for
me to think it's always considered "extremely bad form"

In another thread it was averred that one of the motivations to have
exceptions in a language is to throw them from constructors.
The fact is, just because you throw an exception in the constructor,
that's no guarantee that the object can be GC'ed. It _should_ be, but
you can in fact pass the "this" reference out of the constructor,
allowing it to be held elsewhere, causing the object to be reachable
even though the constructor failed.

One reason why it's bad practice to let 'this' escape the constructor.
But, assuming you write code that's more robust than that, then it's up
to you to ensure any cleanup is done if necessary. Ideally, you'd do
all the things that could throw an exception either outside the
constructor or before doing anything that'd need cleaning up. But
that's not always possible.

One thing that helps is to limit constructors to those tasks directly involved
with instance construction, and not those that do the job of the instance.
IOW, the pattern should not be to do a 'execute()' within the constructor but
to do 'new Foo().execute()'.
I admit, I'm not completely familiar with how the Java run-time manages
the finalizer. ...

But as near as I can tell, in Java every object has a finalize() method
(duh), and that method is always executed before the object is GC'ed,

Not exactly.
requiring the GC to always check the object at least twice for

Not true.
collection. I suppose maybe the run-time looks to see if the method has
been overridden, and only calls it if it has.

That's how it's done. When an object has a "non-trivial" finalizer, the JVM
registers it as such on construction. Only those objects need two GC cycles
to clean up - the first to run 'finalize()' and the second to reclaim the
space. Trivial (do-nothing) finalizers are not run, so those objects with
trivial finalizers only need one GC cycle. That's part of the cost of
overriding 'finalize()' non-trivially.

This is covered in the JLS (amazingly) in s. 12.6.
<http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.6>

Either Bloch covers the dangers and costs of finalizing in /Effective Java/,
or Goetz does in a DeveloperWorks article, or both - my recollection on that
is dim. Google if interested.
 
J

Joshua Cranmer

Lew said:
Either Bloch covers the dangers and costs of finalizing in /Effective
Java/, or Goetz does in a DeveloperWorks article, or both - my
recollection on that is dim. Google if interested.

<http://www.ibm.com/developerworks/java/library/j-jtp01274.html> is the
resource I believe you are referring to, although Bloch also references
it in /Effective Java/ (Item 7: Avoid finalizers).

The overarching message is clear: finalizers are finicky and are not a
reliable substitute for C++ destructors.
 
L

Lew

Peter said:
But there still is no way for an object to advertise that in spite of  
having a finalizer, all of the necessary cleanup has already been done.  
Right?

Not AFAIK, assuming I understand what you mean by "advertise".

The phrase "in spite of having a finalizer" bothers me. In the
general case, finalizers are the wrong way to do "necessary cleanup".
The two finalizer use cases in the literature I've read are just-in-
case last-ditch damn-you-should-have-done-this-already tasks, and
cleanup of JNI memory whose lifetime needs to exactly match the owning
object's. Using finalizers for anything necessary is a recipe for
failure.
 
L

Lew

Thomas said:
However, since finalizable
objects necessarily survive their first collection, it makes little
sense to allocate them in the young generation, since it would end up in
the old generation anyway.

Not necessarily. It takes more than one GC cycle for an object to
move from to the tenured generation.
This means that in that hypothetical GC implementation, you pay for half
of the extra cost associated with finalization when the instance is
created, even if finalization is suppressed afterwards.

As I pointed out in my previous post, suppression of finalization is
already in Java, so adding it would be redundant.
 
L

Lew

Peter said:
As you say, the finalizer is not part of normal operation.  It's there as  
a fail-safe.  So, for classes that do need that fail-safe in order to  
ensure that buggy client code doesn't break things, it's useful as a  
performance optimization for the run-time to provide a way for the class  
to inform the run-time that the fail-safe behavior isn't needed, because  
the requisite cleanup has already been done.

There is such a way - do not override 'finalize()'. That informs the
runtime "that the fail-safe behavior isn't needed".
It occurs to me that Java could in fact include this.  

It already does.
If the run-time tracks whether the finalize() method has been called, as opposed to  
tracking whether the _run-time_ calls the finalize() method (I realize the  
difference is subtle, but it's there), then if the class uses an explicit  
call to finalize() in order to perform its own cleanup, or even simply as  

In Java, the class should not call 'finalize()' - that's not the
purpose. The purpose of 'finalize()' is to work with GC in certain
rare scenarios. It is not as general-purpose as the .NET finalizer.
The way the class does its own cleanup is to call some method that
does not override 'finalize()'.
a signal to the run-time that it's been cleaned up, then that would allow  
the run-time to know the cleanup has been done and not put the object into  
the list of objects needing finalization.

Again, Java has that feature as the default behavior. Unless you
override 'finalize()', the runtime does not put it in the list of
objects needing finalization.
Whether Java does in fact do that, I don't know.  But it could.

In effect, it does, but it does it the other way around from your
description. In Java, the default behavior is not to put the object
into the finalization queue. You signal to the runtime that the
class's objects do need to be finalized by overriding the 'finalize()'
method (nontrivially).

In Java, the best practice is to call some method that doesn't
override 'finalize()' to do cleanup, then remove all references to it
as a signal to GC to clean it up. Only in the very rare use cases
where you need to tie some action to GC-time cleanup do you override
'finalize()' nontrivially.
 
L

Lew

Peter said:
I don't see why that's necessary.  In this "hypothetical GC  
implementation", it would no longer be true that "finalizable objects  
necessarily survive their first collection", and there would be no reason  
to try to optimize them out of the young generation.

Assuming one is trying to optimize for the common and correct case, such a  
hypothetical implementation would simply assume that finalizable objects  
would not actually need to be finalized, and would thus treat them as any  
other object for the purposes of allocation.

That's how Java works now, in effect. You don't override 'finalize()'
in the first place unless the object "actually need to be
finalized".
And sure, an object that does wind up needing to be optimized would have a  
performance impact.  Oh well.  That's life.  All the better reason to make  
sure the code is correct in the first place.

That's how Java works now, in effect.

Java is not .NET.
 
E

Eric Sosman

Peter said:
[...]
Using finalize() to release a JNI peer is all right. Using
finalize() as a last-ditch safety net (complaining loudly that a
bug has been detected) is a little shadier, but still defensible.
I haven't seen *any* other use cases for finalize() that I found
convincing. YMMV.

So, I gather what you're talking about is the question of writing
classes with finalizers in the first place, rather than someone writing
code that relies on using the finalizer instead of cleaning up the
instance correctly? If so, then I misunderstood what you meant. But
I'm still not clear on why the optimization would encourage bad behavior?

That is, how would introducing an optimization in the GC system, where
calling the finalizer can be avoided when the object has been cleaned up
properly, encourage people to write classes with finalizers when it's
not appropriate to do so? After all, the presence of a finalizer would
still cause a potential performance issue, and a manifested one if the
instance wasn't cleaned up properly (i.e. by calling a close(),
dispose(), etc. method rather than waiting for the finalizer to get it).

I don't think we disagree when the question of when a class ought to
have a finalizer. :) I'm just curious how optimizations to the
finalization behavior of Java would encourage the use of finalizers in
inappropriate situations.

My thought (if it merits the term) is that we're talking
about an optimization, a technique that would reduce the
performance penalty of implementing a non-trivial finalize().
If the mere presence of finalize() becomes less painful, people
will use it more -- even when they oughtn't.

There *should* be deterrents to suspect behavior: not
outright bans, but deterrents and not encouragements. Or to
put it in B-movie terms:

There Are Things Man Was Not Meant To Know

(cue the creepy music).

Just a prejudice, really ...
 
L

Lew

Peter said:
A class can't decide after the fact whether to override finalize() or
not. It's part of the class definition. It can't conditionally
"un-override" the method if the client code correctly calls close(),
dispose(), etc.

That doesn't pose much of a problem in Java.
At the same time, a class that contains resources that Java can't
correctly clean up on its own really _must_ override finalize, to make
sure that buggy client code that fails to call close(), dispose(), etc.

The Java-idiomatic answer to that is not to write buggy code. If the
programmer takes the thought to write a 'finalize()' to do such things, they
shouldn't have done that; they should have written correct code "to call
close(), dispose(), etc." in the first place.
does not cause the entire system to fail (for example, file or network
i/o objects that retain references to expensive system resources that if
not correctly cleaned up eventually would result in the host system
exhausting those resources).

The advice in Java is, "Don't do that."
Assuming the client code uses the object correctly, and calls close(),
dispose(), etc. as required before it's done with the object, the
finalize() method won't have any real work to do. The cleanup will
already have happened.

And therefore one would not write a 'finalize()' method. Instead, one would
write correct code that "calls close(), dispose(), etc. as required before
it's done with the object".

The problem in Java with what you suggest is that there is not any guarantee
that an object will be GCed, ever, and if so, when, so if one has a critical
need to clean up resources, 'finalize()' is exactly the wrong place to rely on
to do it. The GC mechanism only tracks heap; it doesn't pay attention to what
other resources the program might waste.
The fact is, the need for a finalizer is the same in Java as for .NET,
and the opportunity to avoid calling the finalizer is the same in both.

No, it is not. The need in Java is to write a method other than a
'finalize()' override that does such things. The opportunity to avoid a
finalizer in Java is not to override 'finalize()' but to do such mandatory
tasks explicitly and not rely on GC to do it for you.
I know for a fact how .NET does it. Do you know for a fact how Java
does it? Or does not do it, as the case may be?

I do know for a fact what most JVMs do, in particular Sun's, which is that a
trivial (non-overridden) 'finalize()' is not actually run, but a non-trivial
finalizer is run during the first attempt to GC the object and actual
collection is deferred until the next attempt. It is that the JVM marks
non-trivially finalizable objects as such in order to know to do that. It is
that trivially finalizable objects only take one GC to clean up.

I suppose it is possible that there are JVMs that do otherwise. I'm mostly
familiar with the information pertaining to Sun's, not that I'm an expert.
What I've stated above is factual with respect to that.
 
L

Lew

Peter said:
I hope that between Eric's and my own previous reply, you understand how
you've misconstrued what I've written.

I have not.
A brief reiteration: when I write "the fail-safe behavior isn't needed",
I'm not talking about for the class generally. I'm talking about for a
specific instance of the class, where the class _does_ need the
fail-safe behavior, but because of the way the _instance_ has been used,
the _instance_ itself can safely skip that fail-safe step during garbage
collection.

Apparently you misconstrued my point, which is that the need to do such a
thing is obviated by using something other than a 'finalize()' override to do
that cleanup.
 
E

Eric Sosman

Lew said:
I have not.

Then you're putting on an awfully good act. It's
fooled me, that's for sure.
Apparently you misconstrued my point, which is that the need to do such
a thing is obviated by using something other than a 'finalize()'
override to do that cleanup.

Apparently you've missed what both Peter and I are
discussing, which is the use of finalize() as a last-gasp
safety net, a piece of defensive coding that may (*may*)
help detect and perhaps recover from somebody's failure to
use a class correctly.

Imagine: I write a class that requires cleanup, and I
endow it with a dispose() or close() or sayonara() method
to do that cleanup, and I write Javadoc informing the user
of my class that the method is to be called when the class
instance is no longer needed. All well and good, and if
every programmer who uses my class heeds the Javadoc and
never makes a mistake, things are hunky-dory.

But then it occurs to me that some programmers are as
fallible as I am myself, and may forget to call dispose()
or make some little error that allows the dispose() call
they've written to be bypassed. And I think, "Wouldn't it
be helpful if my class made an effort to alert the programmer
about the bug?" So I give my class a finalize() that does

protected void finalize() throws Throwable {
try {
if (not_disposed_yet) {
ringTheAlarmBells();
dispose();
}
}
finally {
super.finalize();
}
}

That is, it does nothing out of the ordinary if the instance
has been cleaned up as per contract, but raises red flags if
an instance becomes garbage prematurely. Clear?

In a perfect world this finalize() never does anything,
because programmers never make mistakes. If that's the world
you live in then I envy you, and I imagine others do, too.
But some of us have not yet attained the degree of enlightenment
that allows us to inhabit your Nirvana, so we're reduced to
relying on imperfect but practical measures. Pity us if you
will, but don't mock us, okay?
 
L

Lew

Eric said:
....
Apparently you've missed what both Peter and I are
discussing, which is the use of finalize() as a last-gasp
safety net, a piece of defensive coding that may (*may*)
help detect and perhaps recover from somebody's failure to
use a class correctly.

But that's exactly the use case I already said is valid for 'finalize()'.
Imagine: I write a class that requires cleanup, and I
endow it with a dispose() or close() or sayonara() method
to do that cleanup, and I write Javadoc informing the user
of my class that the method is to be called when the class
instance is no longer needed. All well and good, and if
every programmer who uses my class heeds the Javadoc and
never makes a mistake, things are hunky-dory.

Of course.
But then it occurs to me that some programmers are as
fallible as I am myself, and may forget to call dispose()
or make some little error that allows the dispose() call
they've written to be bypassed. And I think, "Wouldn't it
be helpful if my class made an effort to alert the programmer
about the bug?" So I give my class a finalize() that does

protected void finalize() throws Throwable {
try {
if (not_disposed_yet) {
ringTheAlarmBells();
dispose();
}
}
finally {
super.finalize();
}
}

That is, it does nothing out of the ordinary if the instance
has been cleaned up as per contract, but raises red flags if
an instance becomes garbage prematurely. Clear?

Again, that is one of the two use cases I already proffered as legitimate for
'finalize()' overrides.
In a perfect world this finalize() never does anything,
because programmers never make mistakes. If that's the world
you live in then I envy you, and I imagine others do, too.
But some of us have not yet attained the degree of enlightenment
that allows us to inhabit your Nirvana, so we're reduced to
relying on imperfect but practical measures. Pity us if you
will, but don't mock us, okay?

Mock you? Huh? WTF?

You laid out a scenario here that I already mentioned upthread as perfectly
legitimate for overriding 'finalize()'. There's no disagreement there. I
have used 'finalize()' overrides that way myself, since the beginning of my
Java programming career.

As to Peter's comment that
people who ... do the proper cleanup shouldn't have to suffer
the overhead of the finalize() method

The scenario offered there was for long-running apps where you can more or
less predict that GC will eventually hit the 'finalize()' method. In that
situation, the optimization suggested, which I do see BTW, will not make much
observable difference. Objects that truly need the cleanup safety net will
have it, and will take two GC cycles to clean up. The critical resources, if
not correctly cleaned up prior to 'finalize()', will get cleaned up in the
first GC cycle as things stand right now in Java. The only "inefficiency" is
that the object memory will not get cleaned up until the second cycle. This
is very small, smaller still if you follow best practices to isolate the
'finalize()' override to a minimal helper class that manages the resource(s).
So we're talking about adding a language feature, suppressible finalization,
that will "optimize" something that represents very little overhead in
correctly-written code to begin with.

I see your point that the small overhead of waiting an extra GC cycle to free
a small amount of heap memory is a benefit to suppressing finalization
instance by instance. I don't see that that small benefit is worth modifying
Java for.
 
A

Arne Vajhøj

Lew said:
In another thread it was averred that one of the motivations to have
exceptions in a language is to throw them from constructors.

That someone wrote it in a usenet posts does not necessarily make
it true.

But it is a case where a return value is not possible.
One thing that helps is to limit constructors to those tasks directly
involved with instance construction, and not those that do the job of
the instance. IOW, the pattern should not be to do a 'execute()' within
the constructor but to do 'new Foo().execute()'.

There are some cases where an exception in the constructor seems
natural.

IO classes and FileNotFoundException is one example.

Arne
 
A

Arne Vajhøj

Peter said:
At the same time, a class that contains resources that Java can't
correctly clean up on its own really _must_ override finalize, to make
sure that buggy client code that fails to call close(), dispose(), etc.
does not cause the entire system to fail (for example, file or network
i/o objects that retain references to expensive system resources that if
not correctly cleaned up eventually would result in the host system
exhausting those resources).

There is just that little problem that it does "make sure" of that.

Arne
 
A

Arne Vajhøj

Eric said:
The hoped-for optimization -- which, as far as I know, Java does
*not* support -- would be a way for the dispose() method to inform
the GC that it need not call finalize() for an already-dispose()d
Thing instance. To look at it another way, the optimization amounts
to moving `if (! disposed)' out of finalize() and into the GC,
which might be able to do it with less total overhead.

Whether such an optimization would be Good or Bad seems unclear.
For correctly-used objects it could simplify finalization to the point
of eliminating it. On the other hand, it might encourage people to
rely on finalize() in situations where they shouldn't; I can almost
hear the C++ converts saying "So *that's* how Java does destructors!"

I think it would be solution to a non existing problem.

How often will code use unmanaged resource that needs cleanup
and having some finalizer code run and figure out that it does
not need to do anything have a noticeable performance impact?

Most managed resources are pretty expensive to "open" and
"close" and an extra method call that test if something is
null (or similar) should mean nothing.

Arne
 
A

Arne Vajhøj

Peter said:
Can you elaborate on why such a system would encourage incorrect use of
finalizable objects?

If a C++ convert sees something that looks like the destructor he has
been looking for and now it is optimized, then he (or she) will be a
bit tempted to sprinkle them all over the code.

Arne
 
A

Arne Vajhøj

Peter said:
Your reply is redundant at best, and meaningless or wrong at worst.

What is the antecedent of "it"? If it's "a class", then you're just
reiterating what I wrote. If it's "Java", then by definition your
statement is wrong, because the resources I'm writing about are those
that Java specifically cannot clean up.

What exactly is it that you're trying to add to the discussion here?

That the use of finalizer does *not* make sure that buggy client code
that fail to call close does not cause the entire system to fail.

Arne
 
A

Arne Vajhøj

Peter said:
Well, it's apparently a "noticeable performance impact" in enough
situations that it was deemed a useful feature for .NET.

It's possible that was a useless optimization for .NET, but it seems to
me that unless you have first-hand evidence to that effect, it's silly
to try to assert that that's actually the case. It's at least as likely
that Microsoft knew what they were doing when they included that
optimization as it is that your intuitive guess about whether it's
useful or not is correct.

Typical managed resources relate to IO.

IO typical is rather expensive (extremely in wall time but also to
some extent CPU time due to lots of layers to call though).

Checking for finalizer and calling a finalizer that does nothing
should be very fast.

That is not guesswork.

It is fact.

There is no reason to believe it will have any impact for a typical
application.
Except that the extra method call isn't just an extra method call. The
need to perform the method call means an object survives an extra GC
cycle, causing marginal overhead during that next cycle due to the extra
cost in traversing the reachable object graph (and that's on top of the
overhead of the method call itself during the previous cycle).

It _seems_ as though for a single object, that overhead would be very
small. But as I know you already know, doing the same small thing a
large number of times can have a significant performance impact. And
while some applications can perform their work with practically no
finalizable objects at all, others use a very large number of them and
might in fact benefit from the optimization.

Repeating it many times does not change the relative impact.

If opening and closing one file takes 10000 times longer than running
the finalizer, then opening and closing a billion files still takes
10000 times longer than running the finalizer a billion times.

Arne
 
A

Arved Sandstrom

Arne said:
Lew wrote:
[ SNIP ]
There are some cases where an exception in the constructor seems
natural.

IO classes and FileNotFoundException is one example.

Arne

The latter seems natural only because that's how the Sun programmers set
the classes up. To me what would seem natural is to call an open()
method on a File instance and either have a File[Input|Output]Stream
returned, or have a FileNotFoundException thrown at that point (if you
want to go with an exception).

What java.io.File should really be called is java.io.FileName, or
something similar. If there was then still a java.io.File class, some
of the methods (like the ones that check permissions) would logically
stay there, and one would add methods like open() and close(). The
FileInputStream or FileOutputStream would simply be used for reads and
writes.

Just my opinion.

AHS
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top