Bug #22566 | DBConnection object being garbage-collected too early by Java 1.5 | ||
---|---|---|---|
Submitted: | 21 Sep 2006 21:07 | Modified: | 8 Nov 2006 22:25 |
Reporter: | dan f | Email Updates: | |
Status: | Not a Bug | Impact on me: | |
Category: | Connector / J | Severity: | S2 (Serious) |
Version: | Connector/J 5.0.3 | OS: | Linux (Linux) |
Assigned to: | Mark Matthews | CPU Architecture: | Any |
Tags: | Connection, garbage collection, Java 1.5 |
[21 Sep 2006 21:07]
dan f
[21 Sep 2006 21:08]
dan f
DBConnection.java
Attachment: DBConnection.java (java/*, text), 1.10 KiB.
[21 Sep 2006 21:09]
dan f
DBRatingsSource.java
Attachment: DBRatingsSource.java (java/*, text), 1.21 KiB.
[22 Oct 2006 11:12]
Valeriy Kravchuk
Thank you for a problem report. Please, try to repeat with a newer version, 5.0.4, and inform about the results.
[23 Oct 2006 13:45]
dan f
Tried with 5.0.4. Same problem: dfrankow@gibson (~/windows/work/mysql-read3) % java -Xmx800M -cp 'mysql-connector-java-5.0.4-bin.jar:.' DBRatingsSource /* conn id 0 */ SET NAMES latin1; /* conn id 0 */ SET character_set_results = NULL; /* conn id 0 */ SHOW VARIABLES; /* conn id 0 */ SHOW COLLATION; /* conn id 0 */ SET autocommit=1; /* conn id 8897 */ SELECT userId, movieId, rating FROM user_rating_pairs; Finalizing DBConnection, closing Connection .. ... The "Finalizing" message came out almost right away (within a second or so), LONG before it could have finished reading ratings. It continued to run for awhile before I control-c-ed it. Used latest Java as well: dfrankow@gibson (~/windows/work/mysql-read3) % java -version java version "1.5.0_09" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b01) Java HotSpot(TM) Server VM (build 1.5.0_09-b01, mixed mode)
[8 Nov 2006 12:12]
Tonci Grgin
Hi. I consulted about this with my colleagues and here's what we came up with. Looking briefly at your code I've decided to clasify this report as "not a bug" and here's why: This is incorrect usage; to get a connection, get a result set, forget about the connection, never plan to close the connection. If you're rolling you're rolling your own database code (rather than using spring/hibernate or something) things should look something like this: Connection conn = null; try { .... } finally { if (conn != null) { conn.close(); } } As for "no gc" in 1.4.x my guess is that java 5 has better (or at least different) garbage collection and recognizes that the connection is no longer referenced earlier in the process and it is correct to garbage collect an object which is no longer referenced, even indirectly, by an active thread. As for your last remarks, the speed of gc could be connected to "softly reachable objects". See more in http://java.sun.com/docs/hotspot/gc1.4.2/faq.html. But the main problem is in, I believe, what I wrote above.
[8 Nov 2006 13:41]
dan f
The key is your statement "it is correct to garbage collect an object which is no longer referenced, even indirectly, by an active thread." My expectation was that ResultSet referenced Statement, and Statement referenced Connection. If that is true, then Connection is reachable and shouldn't be garbage collected. Thus, under my expectation it took a long time to find out what was going on. It would be best if MySQL JDBC code met that expectation, all other things equal. Does it? "Softly reachable" is only if objects have soft references. Does it need to have soft references? Sure, it's dodgy to not close the connection. I wouldn't argue it's the best code. It wasn't mine, I was just debugging it. However, MySQL JDBC driver's unexpected behavior wasted a lot of time for me.
[8 Nov 2006 21:32]
Mark Matthews
The driver doesn't use soft references to any instances of the classes you speak of (Connection, Statement, ResultSet), so the issue seems to be the fact that you're relying on a finalizer to clean up your DBConnection instance, which is perhaps no longer _itself_ referenced by anything (but isn't done with it's work?). This might be timing-dependent, which is why a new VM with different GC implementations might trigger it, but it's not a bug in the driver. In general, relying on finalizers to handle "lifecycle" of an object is discouraged in Java, this behavior being one of the reasons.
[8 Nov 2006 22:12]
dan f
Mark-- sorry to communicate through this bug interface, I don't have anyone's email address. Sure, I realize using a finalizer to close a DB connection is bad. It wasn't my code, I was simply debugging it. However, is it true or not that ResultSet refers to Statement, which refers to Connection? If true, the Connection should not be garbage collected. If not true, shouldn't it be true so this confusing thing doesn't happen to someone else?
[8 Nov 2006 22:18]
Mark Matthews
As long as your application retains a reference to something that contains a reference to Connection, then it is definitely reachable. If it's being GC'd before your application releases the reference to the "holder", that's a bug with the VM. Are you sure you're not doing something (multithreaded?) that's causing behavior you're not expecting?
[8 Nov 2006 22:25]
dan f
I forgot: the DBConnection (not referred to by anything) is garbage collected and its finalizer closes the Connection. Yep, bad code. Bug closed.