Issue Details (XML | Word | Printable)

Key: DERBY-557
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Minor Minor
Assignee: Knut Anders Hatlen
Reporter: Knut Anders Hatlen
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
Derby

Client driver gets OutOfMemoryError when re-executing statement without closing ResultSet

Created: 09/Sep/05 12:31 AM   Updated: 15/Feb/06 10:11 PM
Return to search
Component/s: Network Client
Affects Version/s: 10.1.1.0, 10.1.2.1, 10.2.1.6
Fix Version/s: 10.1.2.1, 10.2.1.6

Time Tracking:
Not Specified

File Attachments:
  Size
Text File Licensed for inclusion in ASF works DERBY-557-regression-test-v2.diff 2006-02-12 09:11 AM Knut Anders Hatlen 3 kB
File Licensed for inclusion in ASF works DERBY-557-regression-test-v3.diff 2006-02-15 06:49 PM Knut Anders Hatlen 3 kB
Text File Licensed for inclusion in ASF works DERBY-557-regression-test.diff 2006-02-12 07:47 AM Knut Anders Hatlen 3 kB
Text File Licensed for inclusion in ASF works DERBY-557-regression-test.stat 2006-02-12 07:47 AM Knut Anders Hatlen 0.3 kB
File Licensed for inclusion in ASF works DERBY-557.diff 2005-09-12 06:44 PM Knut Anders Hatlen 4 kB
Text File Licensed for inclusion in ASF works DERBY-557.stat 2005-09-12 06:44 PM Knut Anders Hatlen 0.2 kB
Text File Licensed for inclusion in ASF works derbyall_report.txt 2005-09-12 06:44 PM Knut Anders Hatlen 16 kB

Resolution Date: 15/Feb/06 09:50 PM


 Description  « Hide
When re-executing a statement without closing the old ResultSet, some of the old ResultSet's resources are not released, and the network client will eventually get an OutOfMemoryError.

Example:

Connection c = DriverManager.getConnection("jdbc:derby://localhost/mydb");
PreparedStatement ps = c.prepareStatement("select * from sys.systables");
while (true) {
ResultSet rs = ps.executeQuery();
}

This code will run for some time and then throw an OutOfMemoryError. Same thing happens with Statement instead of PreparedStatement. If rs.close() is added in the loop, the code works. Explicitly closing the ResultSet should not be necessary according to this quote from the JDBC 3.0 spec:

  For Select statements, the statement is complete when the associated result set is closed. The result set is closed as soon as one of the following occurs:
     - all of the rows have been retrieved
     - the associated Statement object is re-executed
     - another Statement object is executed on the same connection

 All   Comments   Work Log   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
Knut Anders Hatlen added a comment - 09/Sep/05 12:39 AM
Quoting myself from derby-user:

> FYI, I had a look in the client driver code. It seems like only
> markClosed() is called on the open ResultSets when a statement is
> re-executed. The difference between close() and markClosed() is
> basically that close() additionally checks whether it should
> auto-commit, nulls out the cursor and meta data, and calls
>
> connection_.CommitAndRollbackListeners_.remove(this);
>
> Could this be our memory leak? Is there any situation where one
> shouldn't call close() on the result sets when re-executing?

After I sent this mail, I ran a test with some println-statements in the client driver. When the OutOfMemoryError was thrown the CommitAndRollbackListeners_ list had around 17000 elements when using Statement, and around 300000 elements when using PreparedStatement.

Knut Anders Hatlen added a comment - 12/Sep/05 06:44 PM
Attached a patch which fixes the bug. The patch ensures that the ResultSets associated with a Statement/PreparedStatement are removed from CommitAndRollbackListeners_ in org.apache.derby.client.am.Connection when the statement is re-executed.

I have run derbyall with only one error (wrong length of encryption key, not related to the patch). I have also run the program in the problem description (both with Statement and PreparedStatement), and the memory usage doesn't increase over time.

Could someone review this patch?

Thanks!

Kathey Marsden added a comment - 16/Sep/05 10:54 PM
Thanks Knut for the patch.
It looks good and I committed it to the trunk.

Date: Fri Sep 16 06:52:14 2005
New Revision: 289539

URL: http://svn.apache.org/viewcvs?rev=289539&view=rev


A couple of questions though.

1) What do you think about adding a test.? The heap can be set using jvmflags in an app_properties file as we do in tests/largedata

2) Do you want this to go into the 10.1.2 release? If so, you can just merge and test in your workspace and then post the svn merge command here and I'll port it to the branch. I think it would be a great to address some of these memory issues for 10.1.2.



Knut Anders Hatlen added a comment - 16/Sep/05 11:42 PM
Kathey,

Thanks for committing. Answers to your questions follow.

1) I could write a test like "run this loop for x minutes and see if an OutOfMemoryError is thrown". With a small heap it would run out of memory fairly soon. Is this the kind of test you want? Where does such a test belong? derbylang? derby*mats?

2) I merged the changes and tested with 10.1 earlier today. Didn't get OutOfMemoryError and derbyall ran successfully (except some encryption tests, as usual). Merge command: svn merge -r 289538:289539 trunk-directory 10.1-directory

Kathey Marsden added a comment - 17/Sep/05 12:19 AM
That sounds fine to me for the test or just some large constant number of iterations.

If you are adding a new test, I tend to think jdbcapi is a good place and something with a name generic enough that we could put in a test for DERBY-210. Alternately you could just change resultset.java to use a small heap if this doesn't add a huge amount of time to the test.

Kathey Marsden added a comment - 06/Oct/05 06:30 AM
Should I go ahead and port this to 10.1 or wait for the test?

Knut Anders Hatlen added a comment - 06/Oct/05 03:33 PM
Kathey, I think you should just go ahead and port the fix to 10.1.

Merge command:

  svn merge -r 289538:289539 https://svn.apache.org/repos/asf/db/derby/code/trunk

I have started working on a general check-that-resources-are-freed
test for DERBY-23, DERBY-210 and DERBY-557, but while doing that I ran
into another resource leak (DERBY-594) that I wanted to resolve first.

Knut Anders Hatlen added a comment - 07/Oct/05 03:59 PM
Fixed in trunk (revision 289539) and 10.1 (revision 306950).

Knut Anders Hatlen added a comment - 12/Feb/06 07:37 AM
Reopening to add regression test.

Knut Anders Hatlen added a comment - 12/Feb/06 07:47 AM
Added a test case for DERBY-557 to jdbcapi/derbyStress.java. I have
verified that the test case fails without the fix.

I had to enable the test for DerbyNetClient. Since the test case for
DERBY-210 currently fails under DerbyNetClient, I disabled that test
case in the java code by adding this to prepStmtTest():

  // Don't run under DerbyNetClient until DERBY-210 is fixed
  if (TestUtil.isDerbyNetClientFramework()) return;

Derbyall ran cleanly.

Could someone please review?

Thanks.

Bryan Pendleton added a comment - 12/Feb/06 08:39 AM
This change looks good to me. The patch applies cleanly to the current trunk. I read through the test code and thought it was fine. With your patch applied, I ran

java -Dframework=DerbyNetClient -Dverbose=true org.apache.derbyTesting.functionTests.harness.RunTest jdbcapi/derbyStress.java

and got the expected results (test passed, with the new print statement appearing in the output as expected).

Knut Anders Hatlen added a comment - 12/Feb/06 09:11 AM
Whops! I forgot to close the connection in the regression test. Uploaded new patch (DERBY-557-regression-test-v2.diff) with conn.close() added. I apologize the noise.

Knut Anders Hatlen added a comment - 15/Feb/06 06:49 PM
Uploading new diff because of conflict with a recent commit.

Bernt M. Johnsen added a comment - 15/Feb/06 09:50 PM
Committed revision 377998.

Knut Anders Hatlen added a comment - 15/Feb/06 10:11 PM
Regression test checked into revision 377998.