finalize() overhead

W

Wojtek

Joe Seigh wrote :
There was no problem with finalize. What happened is the Statement and
ResultSet objects reference the connection internally. You dropped the
reference to your enclosing object and it's finalizer closed the connection
while it was still being referenced and used by the ResultSet object.
You assumed that if your enclosing object wasn't being referenced, that
the objects contained in it were no longer being referenced.

In the following I left out all the try/catch/finally for brevity.

Note to new-comers. DO NOT use this pattern. It is flawed and you may
end up with many connections left open due to when the GC calls
finalize!

public class SQL
{
private Connection conn;

public SQL()
{
conn = Databasae.getConnection();
}

public Data getData()
{
Statement st;
ResultSet rs;
Data data = new Data();

st = conn.createStatement();
rs = st.executeQuery("select id,name from table");

while ( rs.next() )
{
// code to fill data
}

return data;
}

public viod finalize()
{
conn.close();
}
}

and to use this:

-------------------------------
SQL sql = new SQL();
Data data = sql.getData();
sql = null;
-------------------------------

So from my thinking:
- a connection is established in the constructor
- a method retrieves information
- when sql is set tu null, the only reference goes away.
- some time in the future the GC calls the finalize method.

In practice, the connection appeared to be closed before the "while (
rs.next() )" loop completed.

When I made the following change, the problem went away.

public class SQL
{
public Data getData()
{
Connection conn;
Statement st;
ResultSet rs;
Data data = new Data();

conn = Databasae.getConnection();
st = conn.createStatement();
rs = st.executeQuery("select id,name from table");

while ( rs.next() )
{
// code to fill data
}

conn.close();

return data;
}
}

I went back and forth several times between the to ways, and the
results were consistent.
 
?

=?ISO-8859-15?Q?Roger_Lindsj=F6?=

Wojtek said:
Joe Seigh wrote :


In the following I left out all the try/catch/finally for brevity.

Note to new-comers. DO NOT use this pattern. It is flawed and you may
end up with many connections left open due to when the GC calls finalize!

public class SQL
{
private Connection conn;

public SQL()
{
conn = Databasae.getConnection();

I'm a bit qurious about this. What class is Databasae? Is it a pool, a
single connection (a pool of one ;-) or does it generate a new
connection for each request?

If it returns the same connection each time, then this scenario could
happen:

You create SQL(instance 1) which runs to completion. Later you create
SQL(instance 2) which gets a large ResultSet. Both instances now have a
reference to the same connection. Iteration over the ResultSet causes
some garbage so the GC decides to clean up memory. It finds SQL(instance
1) and runs finalize() on it which cases the connection to be closed.
Bad news for SQL(instance 2).

//Roger Lindsjö
 
W

Wojtek

Roger Lindsjö wrote :
I'm a bit qurious about this. What class is Databasae? Is it a pool, a single
connection (a pool of one ;-) or does it generate a new connection for each
request?

It is a pool manager called proxool, Database is a wrapper class.
 
O

Owen Jacobson

It's not best advice. Your main objections seem to be that I'm thinking of
using it on everything which will slow things down, and that I'm going
to use it for deterministic destruction. Neither is true.

As to why java.io, jdbc drivers, etc.. use it? Maybe you've never had to
support a really large code base, or you have and enjoy getting paged at
3 am about something you can't really do anything about at the moment.
Which would you rather support? An application that dies because some
combination of events caused it to execute a section of code that leaked
resources, or an application that could most likely recover those resources
before they ran out completely and issued diagnostic warnings instead.
Either you get this or you don't.

Do you trust the finalizer to release locks for you (or your caller)
if you forget to release them yourself? And do you trust your
(caller's) code to be in a sane state if a forgotten lock is suddenly
released?

Do you trust the finalizer to close sockets for you (or your caller)
if you forget to release them yourself? And do you trust your
(caller's) code to be in a sane state if a forgotten socket is
suddenly closed?

Do you trust the finalizer to close a file handle for you (or your
caller) if you forget to release them yourself? And do you trust your
(caller's) code to be in a sane state if a forgotten file handle is
suddenly closed?

These are the sorts of questions that putting cleanup in the finalizer
should be bringing up for you. In my own case, the answer to all of
them is "No.", so I don't put cleanup in the finalizer and do not rely
on finalizers to catch my own mistakes. Finalizer "cleanup" only
changes one broken state (caller did not clean up properly) into
another broken state (caller did not clean up properly and may have
been unprepared for cleanup); it at best masks bugs and never fixes
them.

You can't truly enforce correctness on code that calls your code, and
attempting to is painful for both your code and your caller's code.
The garbage collector is particularly the wrong tool to try to use to
coerce others with, since it's tuned for managing exactly one
resource: memory.
 

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,780
Messages
2,569,608
Members
45,250
Latest member
Charlesreero

Latest Threads

Top