Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Doing one last thing to a WeakReference

Reply
Thread Tools

Doing one last thing to a WeakReference

 
 
Tom Anderson
Guest
Posts: n/a
 
      06-18-2008
On Wed, 18 Jun 2008, Lew wrote:

> Lew wrote:
>>>> Joshua Bloch, /Effective Java/
>>>> <http://java.sun.com/docs/books/effective/index.html>,
>>>> Item 7, "Avoid finalizers".

>
> Tom Anderson wrote:
>> And Lew, this is especially for you:
>>
>> http://weblogs.java.net/blog/tball/a...ly_a_good.html
>>
>> The evils of finalizers, AND error logging!

>
> That article suggests heavy use of finalizers,


I wouldn't say 'heavy' - just in places where cleanup absolutely has to be
done. I don't think there are many places like that in an application.

Bear in mind that the alternative to using finalizers for this is to risk
the cleanup not being done, which is incorrect behaviour.

> Lew:
>>> They are not guaranteed to run at all.

>
> Tom:
>> Isn't the only situation where they won't run at all if the program exits?

>
> Not in principle, no. If there isn't enough pressure on memory to
> force a collection after the Java object is dereferenced, then
> 'finalize()' will not happen.
>
> OK, yes, because then by definition the program will exit without
> running 'finalize()'.


Gotcha!

I guess there's no useful difference between 'never' and 'not for an
arbitrarily long time', so i take your point.

> Even if it does eventually run, it may have been delayed long enough to
> put pressure on other resources. For example, if 'finalize()' releases
> a resource connection, it may take so long to get around to 'finalize()'
> that the program runs out of available connections.


That's a good point. But this is a reason not to use finalizers as a
general cleanup mechanism, but not a reason not to use them as a backup -
in fact, quite the opposite. If you didn't have the finalizers, and the
code was failing to close all connections properly, you'd run out of
connections with no ability to do anything about it. If the finalizers are
there, the connections will be closed provided that finalization runs.

What alternatives are there? The only one i can think of is using a
timeout, so that if a connection has been idle for a certain length of
time, it gets released. This has the advantage of guaranteeing that
resources will be released within a certain amount of time, but suffers
from the disadvantage of potentially releasing resources while they're
still in use.

Ideally, the code handling the interaction with the resource would hold on
to enough lightweight state to be able to transparently reopen the
connection if it was needed again, so the calling code never got a
SorryIThoughtYouUsingThatAndGotRidOfItException. I once worked on a CORBA
implementation that did this - it had a 'smart reconnect' feature whereby
if the socket was closed, for instance by an error, there was enough
information in the object references to reopen it. In fact, it went one
better, and stashed information from the CosNaming or CosTrading lookup
originally used to find the object, so if the server hosting the object
actually went away, it could find you a substitute object from somewhere
else!

tom

--
forget everything from school - you are programmer
 
Reply With Quote
 
 
 
 
Mark Space
Guest
Posts: n/a
 
      06-18-2008
Tom Anderson wrote:

> That's a good point. But this is a reason not to use finalizers as a
> general cleanup mechanism, but not a reason not to use them as a backup
> - in fact, quite the opposite. If you didn't have the finalizers, and


I think you're making the mistake of thinking of finalizers as
destructor. The right way to do this is just to close the object. You
don't need finalizers at all if you aren't using weak references. Just
close the object.


> What alternatives are there? The only one i can think of is using a
> timeout, so that if a connection has been idle for a certain length of


Try-catch-finally. The "finally" portion is always run.
 
Reply With Quote
 
 
 
 
Tom Anderson
Guest
Posts: n/a
 
      06-18-2008
On Wed, 18 Jun 2008, Mark Space wrote:

> Tom Anderson wrote:
>
>> That's a good point. But this is a reason not to use finalizers as a
>> general cleanup mechanism, but not a reason not to use them as a backup -
>> in fact, quite the opposite. If you didn't have the finalizers, and

>
> I think you're making the mistake of thinking of finalizers as
> destructor.


No, i'm not. I'm quite explicitly not. As i took pains to point out in my
post.

> The right way to do this is just to close the object.


Yes.

And if the client code forgets to close the object? Then what? You just
leak the native resource? Please tell me whether you'd be happy to let
that happen, and if not, how you'd present it. Remember - this is if the
client code forgets to explicitly close.

> You don't need finalizers at all if you aren't using weak references.


Eh? Finalizers and weak references are basically completely unrelated. In
fact, to an extent, they're alternatives, so if you *are* using weak
references, you don't need finalizers!

> Just close the object.


The whole point of my post was about dealing with the case where the
object isn't or can't be explicitly closed.

>> What alternatives are there? The only one i can think of is using a
>> timeout, so that if a connection has been idle for a certain length of

>
> Try-catch-finally. The "finally" portion is always run.


You didn't read what i wrote. There are times when the lifetime of an
object is not tied to a lexical scope. In that situation, you *cannot* use
a try-finally block. It is *not possible*.

Maybe you don't understand how this can be so. Let's try an example.

Consider a server for doing online hotel booking. The application is all
about showing the user a list of hotels, in the same city or whatever, and
letting them compare rooms and prices, then letting them make a choice and
book a room (or several rooms, etc).

The actual hotel booking is handled by a legacy mainframe app, with which
you communicate using a native library. The library lets you open a handle
on a particular hotel, make queries and reservations for that hotel using
the handle, and close the handle. You can only have one handle to a given
hotel open at once. Opening handles is expensive. Use of a handle is
threadsafe. You wrap the handle in a class, which has methods to interact
with it, and a close method. So far so good.

Now you write the client-facing part of the code. There are servlets or
whatever out front, and then a layer of business objects. You have a
session object (could be a stateful EJB, could just be a pojo) which holds
the conversational state. Part of that state is a set of handles to the
hotels which are being looked at. Handles are expensive, but threadsafe,
so you share the handle for a given hotel between all the client sessions
which are looking at that hotel. The session object has business methods
which are called by the servlet layer when user requests come in, and
return with responses. Sessions are created and destroyed automatically by
the servlet container in response to users coming and going.

I'm happy to ignore handle creation for now, but here's the question: how
do you deal with the closing of handles? Where, pray tell, do you put your
try-finally block?

tom

--
Science which is distinguishable from magic is insufficiently advanced
 
Reply With Quote
 
Stefan Ram
Guest
Posts: n/a
 
      06-18-2008
Tom Anderson <> writes:
>You wrap the handle in a class, which has methods to interact
>with it, and a close method. So far so good. you share the
>handle for a given hotel between all the client sessions which
>are looking at that hotel. how do you deal with the closing of
>handles?


I assume that eventually a session will have a termination
event, either when the customers has logged out or when the
session has timed out.

The session has a list of all handle objects it has requested
so far. Upon session termination, all handle object from this
list get a release call by the termination event handler of
this session object.

Since these handles are shared between multiple session, they
keep a reference count, which is decremented upon a release call.

When a hotel access handle is requested by a session, the
handle manager object will look for it in his list of active
handle objects. If it is found there, it will he used. It will
be given to the session, and its reference count will be
incremented by 1.

If a handle object for a hotel can not be found, a new handle
object for this hotel will be created. Its reference count
will be set to 1, and it will be given to the session.

If a new handle object cannot be created because the resources
for handles are exhausted, the manager object will look for
handles with a reference count smaller than 1 and will dispose
them until the new handle object can be created.

If still no new handle object can be created, the manager will
report failure to its caller. The session will display »Sorry,
try again later.« to the user.

 
Reply With Quote
 
Mark Space
Guest
Posts: n/a
 
      06-18-2008
Tom Anderson wrote:

> I'm happy to ignore handle creation for now, but here's the question:
> how do you deal with the closing of handles? Where, pray tell, do you
> put your try-finally block?


A slightly larger issue is, what if your front end code grabs a handle,
stuffs it in a session or application object, and never gives it up?
You'd be obliged to maintain that handle forever, and you'd have a
de-facto resource leak.

So I wouldn't give the handles out at all. I'd keep them in my CRUD/ORM
whatever object, and give the client something else, that wouldn't
matter if the client abuses it or forget to close it. Don't give state
to your clients, it's bad.

This also lets you handle errors more cleanly. What if your legacy
database coughs up a hairball right when the client needs to use it?
Legacy apps don't always have the nicest error handling characteristics.
Separating the two concerns (an object for your clients, and one for
your connection) lets you deal with events like that independently.

Of course, I'm not actually writing your app, so I don't know your
requirements, but that's the first thing that occurs to me. Bogart the
handles, keep your client-side connection object separate. Just hand
the client the data, for example, and some sort of key it can check back
in with. Never pass around a reference, pointer or handle from a lower
level layer to an upper level one.


 
Reply With Quote
 
Lasse Reichstein Nielsen
Guest
Posts: n/a
 
      06-18-2008
Tom Anderson <> writes:

> I'm happy to ignore handle creation for now, but here's the question:
> how do you deal with the closing of handles?


You call the close method. The more relevant question is: *When* should
you close the handle?
If you can answer that, then that is where the close method should be
called. If you can't give a clear answer, then that is the problem.

> Where, pray tell, do you put your try-finally block?


You don't. The lifetime isn't lexical. However, the lifetime is still
managed in some way. It is chosen somewhere that a handle is no longer
worth caching.


Anyway, if it happens to be the best solution to simply let a reference
go out of scope, I'd use a reference queue to catch the weak reference
and close it if necessary.
/L
--
Lasse Reichstein Nielsen -
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
 
Reply With Quote
 
Mike Schilling
Guest
Posts: n/a
 
      06-19-2008
Tom Anderson wrote:
>> Finalizers are hugely expensive to GC - an object with an
>> overridden
>> 'finalize()' takes at least two GC cycles to clean up. This
>> applies
>> therefore to objects that reference it and that it references.

>
> Sure, but "hugely expensive" is hyperbole. Do we have any actual
> numbers on this? I can't imagine that using finalizers on 10, 100 or
> even 1000 files or database connections or whatever is going to make
> much difference to a substantially-sized program. I'd think twice
> about putting a finalizer on every object.


We recently observed that what seemed like an innocent addition of a
small finalize() method to a class of large objects severely impacted
memory usage. With a finalizer defined, the object's memory can't be
reclaimed as quickly, since it has to stay around until the finalizer
thread can run. Admittedly, this was in a test run where the CPU was
kept arterially busy, but the results were enough to make us find a
different approach.

> I'm not sure if there are any guarantees about finalizers and
> running
> out of memory; i'd hope that the spec promises that all objects will
> be finalized before an OOME is thrown, but i don't know if it does.


Suppose the finalizer tries to allocate memory?


 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      06-19-2008
Mike Schilling wrote:
> Tom Anderson wrote:
>>> Finalizers are hugely expensive to GC - an object with an
>>> overridden
>>> 'finalize()' takes at least two GC cycles to clean up. This
>>> applies
>>> therefore to objects that reference it and that it references.

>> Sure, but "hugely expensive" is hyperbole. Do we have any actual
>> numbers on this? I can't imagine that using finalizers on 10, 100 or
>> even 1000 files or database connections or whatever is going to make
>> much difference to a substantially-sized program. I'd think twice
>> about putting a finalizer on every object.

>
> We recently observed that what seemed like an innocent addition of a
> small finalize() method to a class of large objects severely impacted
> memory usage. With a finalizer defined, the object's memory can't be
> reclaimed as quickly, since it has to stay around until the finalizer
> thread can run. Admittedly, this was in a test run where the CPU was
> kept arterially busy, but the results were enough to make us find a
> different approach.
>
>> I'm not sure if there are any guarantees about finalizers and
>> running
>> out of memory; i'd hope that the spec promises that all objects will
>> be finalized before an OOME is thrown, but i don't know if it does.

>
> Suppose the finalizer tries to allocate memory?
>


Or suppose the finalizer leaks a hard-reference of itself?


--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
 
Reply With Quote
 
Tom Anderson
Guest
Posts: n/a
 
      06-19-2008
On Wed, 18 Jun 2008, Stefan Ram wrote:

> Tom Anderson <> writes:
>
>> You wrap the handle in a class, which has methods to interact with it,
>> and a close method. So far so good. you share the handle for a given
>> hotel between all the client sessions which are looking at that hotel.
>> how do you deal with the closing of handles?

>
> I assume that eventually a session will have a termination
> event, either when the customers has logged out or when the
> session has timed out.
>
> The session has a list of all handle objects it has requested
> so far. Upon session termination, all handle object from this
> list get a release call by the termination event handler of
> this session object.
>
> Since these handles are shared between multiple session, they
> keep a reference count, which is decremented upon a release call.


Yes. Reference counting is a good solution to this problem, probably the
best one.

And it's a solution which doesn't involve try-finally.

tom

--
IT'S OVER NINE THOUSAND!!!
 
Reply With Quote
 
Tom Anderson
Guest
Posts: n/a
 
      06-19-2008
On Thu, 19 Jun 2008, Lasse Reichstein Nielsen wrote:

> Tom Anderson <> writes:
>
>> I'm happy to ignore handle creation for now, but here's the question:
>> how do you deal with the closing of handles?

>
> You call the close method. The more relevant question is: *When* should
> you close the handle?


Yes, that's what i meant with "deal with the closing of handles".

> If you can answer that, then that is where the close method should be
> called. If you can't give a clear answer, then that is the problem.


Yes, that is the problem. I'm interested in hearing about solutions.

>> Where, pray tell, do you put your try-finally block?

>
> You don't. The lifetime isn't lexical.


EXACTLY! This is the point i was trying to make.

> However, the lifetime is still managed in some way. It is chosen
> somewhere that a handle is no longer worth caching.


Ah, but where that "somewhere" is is the difficult bit.

> Anyway, if it happens to be the best solution to simply let a reference
> go out of scope, I'd use a reference queue to catch the weak reference
> and close it if necessary.


Okay, sounds fine to me.

tom

--
IT'S OVER NINE THOUSAND!!!
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Movie/DVD Review - One Last Thing... John Metzger DVD Video 0 06-13-2006 08:04 PM
One last thing about SocketServer rbt Python 1 10-10-2005 01:42 PM
one thing solved, but other terrible thing occur... Zam ASP General 1 03-14-2005 06:09 PM
How to use WeakReference in a HashMap? Xavier Tarrago Java 5 06-19-2004 05:08 PM
Detecting when a WeakReference gets cleared. Dave Rudolf Java 2 10-21-2003 12:59 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57