Now the reason its standard practice at our place to close resultsets
that you opened, is because we had this program which extracted data
from the DB and it ran a couple of thousand queries on some of the
larger datasets that the clients have. What we experienced was it
would get so far and get the out of memory exception, and the way we
fixed it was to hunt down all the resultsets which weren't being
closed, this was about two years ago...
The other day this new guy told me that you dont need to close
resultsets because the GC will come along when memorys getting low
and will close them for you and tidy everything up.
Also when I worked with a company starting with the letter "O" and
ending in "cle" for a short while I noticed that they also never
bothered closing the resultsets, when I asked the programmer who wrote
it why not he said that when you close the connection then the
resultset will be closed and there is no reason why you should bother
closing them beforehand, but they were experiencing "maximum open
cursors exceeded" errors in the app and didn't know why, although they
were adamant it wasn't due to not closing resultsets...
So my question is, do you actually need to close the resultsets or
not ?
the app is running in 1.3.1 talking to a SQL DB if that makes any
difference...
PreparedStatement stmt = connection.prepareStatement("SELECT ...");
try
{
// Bind Java to SQL binding variables
ResultSet rs = stmt.executeQuery();
try
{
while(rs.next())
{
// Handle record
}
}finally{ rs.close(); }
}finally{ stmt.close(); }
/Casper
Spring's JdbcTemplate appears to do this too:
http://springframework.cvs.sourceforge.net/springframework/spring/src/org/springframework/jdbc/core/JdbcTemplate.java?revision=1.136.2.1&view=markup
Anyone know what FindBugs says about not closing JDBC resources when
done with them?
Stephen
-Dave
Channeling my friend Mr. Carl Quinn here as well, I would remind you
that the Java spec doesn't give any promises of when or even if an
object will be GC'd and finalized. If you have a long running
application, and GC doesn't happen to kick in for that object, it
could be held open indefinitely. Most shops I have worked (the current
one included) have rules about putting any kind of cleanup in a
finalizer, and recommend always using try-finally to clean up after
yourself instead.
I personally believe the O*cle folks who were adamant about the cursor
limit not being a result of too many open results sets was probably in
a bit of denial. I don't know their implementation specifically, but I
would have thought this was almost certain to be the cause. Either
way, cleaning up results sets when they are finished with sounds like
a very good idea.
Cheers
Dick
So, (that's an official Posse 'So'), even if some driver to some
database SEEMs to be working without close, it may not work in a
subsequent driver version, another driver, or another JVM. Connection
pools can hide you a bit from the real implementaton, but at the end
of the day, you can never realy be sure.
Its funny how people swear by things because they seem to work. We
get a free lunch with GC for the most part. It's not too much to ask
to close the resources which say they require it. :)
Cheers,
Tobias
In my experience, this is a terrible practice. It assumes GC will get
invoked before you run out of database resources, which is not always
a valid assumption.
2. O*cle guy not closing ResultSets because Connection#close() calls
closes them.
This is not as bad, in my opinion, but I still wouldn't do it. Even if
your JDBC Driver were 100% compliant, you aren't necessarily
interacting with the driver classes directly (e.g., you may be
accessing them through delegates provided by your connection pool).
Your actual implementation may defer ResultSet closing, for instance.
Too much can potentially go wrong.
BTW, can we really trust a company that gave us "VARCHAR2" and
"DUAL"? ;)
On Jul 26, 8:38 am, Duncan Wild <duncan.c.w...@gmail.com> wrote:
A long time ago, on a large project on which I was a consultant we had
a memory leak. You;d only see it in soak testing when you ran loads
and loads of messages through (it was very heavy on the MQ) and
eventually the testing guys found that the JVM process size would
increase by ~8 bytes per message received. It didn't vary with
message size. What was going on? We turned our profiling tools on it
so we could see where the memory was going but found nothing. "How
could this be?" the customer thought. "Java can't memory leak". It
didn't help that At this time I was working for the folks who had
invented Java (starts with "S" and ends in "un"if you need help with
that one) and so the finger of blame as far as they were concerned was
pointing firmly at us.
To cut a long story short we spent ages looking for it. The customer
was convinced it was in our (S-U-Ns) code. It got very political and
all the while we still couldn't find the source, until one day we
found it, quite by accident. You'll have guessed that it was a
resource which was being opened and then never closed; in our case
ZipInputStream. What they'd done was to use this to get access to
some info from a file each time a message was received. Problem was
in their code they'd never closed the reader once they were done.
(Note we'd asked them if they had always closed things they opened and
they swore blind they had) "No problems, It'd be collected by GC
after it was freed at the end of the try block right?" Errrr right-
ish. It turns out, much to their surprise, that GC can only clean up
Java pieces. If there is native code (such as there was here to access
the native filesystem), this will be left behind; unless you give the
API the chance to clean it up for you. Forget and you'll leak C code
within your JVM process but have a darn hard time finding the source
of it.
The moral of the story? Always clean up after yourself. Especially if
there is a native component to your API (JDBC drivers anyone?)
Regs, Andrew
modern java VMs use an Eden type garbage collectors: A single smallish
block of memory is where newly minted objects start their lifecycle.
This is 'eden'. Once eden is full, only those objects which are still
referenced someplace get copied into the proper heap, and then eden
gets reused. Whichever objects no longer held references are thus
silently overwritten. This makes eden type garbage collecting work
faster than C code - in C code, calling the deconstructor takes some
time, whereas in java 95%+ of all objects deconstruct in zero time.
Because finalization imposes extra work, anything anywhere that has an
explicit finalizer must always graduate from eden. For small
frequently created objects (like strings and other small fries), this
is a huge performance hit.
Database connections are probably far too heavy weight to worry about
the eden penalty.
-However-, I'm virtually positive JDBC resources all already use this
technique - their finalizers clean them up. The problem is, in a java
VM running with a large heap, or written in such a way that it doesn't
create all that many objects that graduate eden but then get discarded
soon after that (THOSE are the objects that the garbage collector will
actually clean up. Eden objects get cleaned up so fast, you never
notice) - actual garbage collection and the related finalization can
take many minutes.
I don't mean to sound condescending - from the tone of your post I
think you already know all this. Just clearing up some things for
interested readers who don't know this stuff.
> a finalizer somewhere in the mix that will /eventually/ do this. You
> should /still/ do the explicit cleanup, of course, so that this stuff
> can be cleaned up in a quick, efficient, and timely manner (whereas
> finalizers don't really meet any of these criteria), but the finalizer
> safety net should still be there. If for some reason the finalizer is
> too expensive (they're far from free), then at /least/ the API should
> have a huge Javadoc warning stating the severe consequences of not
> cleaning up and explaining that the expected finalizer is missing as
> making those who /do /cleanup properly pay the performance penalty was
> deemed inappropriate, unfair, etc. I believe the vast majority of cases
> shouldn't force one to choose between /good /(not perfect) performance
> and safety, though -- in which case safety shouldn't be sacrificed.
>
> On a related note, we spent a *long* time trying to track down a
> horrific memory leak in a customer system. It appeared many critical
> class' finalizers were not being run /*at all*/ (I'm not talking running
> slowly, I'm talking /never/). It was eventually tracked down to a
try {
Connection cn = ....;
Statements st = cn.createStatement();
ResultSet rs = st.executeQuery();
} finally {
rs.close();
st.close();
cn.close();
}
If the rs.close() throws an exception, the Statement and Connection
will not be closed (leaks will occur) and you will lose the original
exception (really bad and expensive if it happens in production). So
I normally do:
// Repeat for Statement, Connection
void close(ResultSet rs) {
if (rs != null) {
try {
rs.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
try {
Connection cn = ....;
Statements st = cn.createStatement();
ResultSet rs = st.executeQuery();
} finally {
close(rs);
close(st);
close(cn);
}
Mike.
Bummer there's no common interface such as java.io.Closable, huh?
Due to the fact that SQLException and IOException are checked exceptions
it's impossible to use java.io.Closable here - bloody checked exceptions...
Hence we're using a 'duck type variant' using reflection invoking
'a Close() method' on a given Object here. Kinda Groovy :)
Marcus
Java is not allowed, during the continued running of a VM, to avoid
running finalizers when objects are tossed. However, it is allowed to
keep a collectable object in memory (and thereby, never finalize it)
indefinitely. This makes absolutely NO difference from the
programmer's perspective in the behaviour of finalizers (specifically:
Your current opinion that finalizers are an optional thing you should
never rely on is for all practical purposes true), but once you get
into VM nitty gritty, the distinction is important. In this case,
while they are optional from the standpoint of a programmer, they are
totally NOT optional from the standpoint of a performance analist. A
finalizer will make GC of the specific object anywhere from a little
slower (cost of running it) to a whole lot slower (cost of enforced
unneccessary graduation from eden).
NB: the term 'graduation' is something I made up. There's another word
with similar meaning that's commonly used in discussions but I forgot
what it was. Just an FYI for those trying to google this stuff. 'eden'
is the official term for this scheme though.
http://java.sun.com/javase/6/docs/api/javax/sql/PooledConnection.html
Has some interesting stuff to say about the javax.sql.PooledCennction
If I'm reading it right, it is basically saying that you should
_always_ call close() on your connections and prepared statements, but
that if you somehow manage to call the wrong close() then all heck
will break loose.
Yep. Right. Got the same class as well - the ever lasting 're-invention-of-the-wheel'.
It's obvious that one needs such an interface (SWT Disposable and JDK Closeable).
But it seems it's not as obvious as required.
No ducks involved? And what is the dynamic proxy all about if not ducks? :)
Marcus
_______________________________________________________________________
Jetzt neu! Schützen Sie Ihren PC mit McAfee und WEB.DE. 3 Monate
kostenlos testen. http://www.pc-sicherheit.web.de/startseite/?mc=022220
Without wheel reinventions we would have chrome alloys. :)