Chris,

Richard,

Richard S. Huntrods wrote:
| In my code I was calling resultSet.close(), but not statement.close().

That'll do it.
Actually, fixing it did NOT help. See more below...


| The problem is, even though I verified (debug statements) that the call
| is being made, the memory is STILL not being released. If I run the same
| large query 3 times in a row, my memory use triples. Even if I log off
| the session (my application) and invalidate the session, the memory is
| still locked up and cannot be freed by the JVM.

Can you post some (sanitized) code? Maybe you're still missing something.
My sanitized code looks exactly like the code you posted below. I put all my actual database work inside a DBMS class so that I could change it out anytime without messing the application, and it's worked well. Each different type of database access has it's own method (lookup, lookupList, insert, delete, update, etc...). Each method opens ONE connection, ONE statement and gets ONE resultSet. When I'm done, I close the resultSet and (now) the statement. I also have full exception handlers plus the necessary finally clause.

I also know from running my application that no exceptions are occurring during the memory leak (no output to the debug file).


Remember that you can't just close the statement when you're done with
your method... if you use multiple Statements and ResultSets, you have
to close them as you so. You also have to make sure that you have a
finally block that closes them in case of an exception condition.
I never use multiple statements and resultSets. That's just asking for trouble, IMO. ;-)


I've posted it before, but I'll to it again because it bears repeating:
here is the proper way to write JDBC code:

    Connection conn = null;
~        PreparedStatement ps = null;
~        ResultSet rs = null;

~        try
~        {
~            conn = getConnection(); // however you get your connections

~            ps = conn.prepareStatement(...);  // your query

        // set params, etc.

~            rs = ps.executeQuery();

        // do whatever you need to do with your ResultSet
~        }
~        finally
~        {
        if(null != rs) { rs.close(); } catch (SQLException sqle)
        { /* log this error! */ }
        if(null != ps) { ps.close(); } catch (SQLException sqle)
        { /* log this error! */ }
        if(null != conn) { conn.close(); } catch (SQLException sqle)
        { /* log this error! */ }
~        }

Yep - my code looks pretty much just like this.

I wrote a method in a utility class that does everything in the finally
block -- it makes the code much easier to read IMO.
Agreed. Me too.


Note that if you need multiple Statements, you should either use them
serially, and close each statement before you move onto the next one
(and re-use the local variable), or you should define them all outside
of the try/finally block and make sure they are closed under all
conditions. If you don't do this, you'll leak memory.

If you are using transactions, remember that you must catch /every
exception that can possibly occur/ (yes, even Errors and
RuntimeExceptions) and make sure you do a rollback before you close
everything.

| So what am I missing? I was sure that adding the code to close my
| statements would fix the problem.

Is it possible that the code you're looking at is good, but some other
code has a similar leak but is yet to be fixed.
As I said, 3.0.17 works PERFECTLY (no memory leaks, memory use hovers around 50 megs of stack. With 3.1.10 and newer, memory use immediately starts to climb immediately. It quickly reaches (within 30 min) 500 megabtyes ( of a 1 gig stack) and after an hour it hits the stack limit and tomcat crashes. This is even with the "UseParallelOLDGC" garbage collector in use to compact the old stack (without it the system crashes even sooner due to fragmenting).


| So - does anyone know what the major change was between 3.0.17 and
| 3.1.10 that would have such a dramatic effect?

http://dev.mysql.com/doc/refman/5.0/en/cj-news.html

It's possible that newer versions of the JDBC driver more properly
adhere to the JDBC specification which results in memory leakage
(because JDBC expects you to code in very rigid ways, including cleaning
up your own memory messes ;) .
That's what I am thinking as well - or a newer JDBC spec. Otherwise how to explain a ONE DAY release date difference by a MAJOR version change (3.0.17 on June 22/05 -> 3.1.10 on June 23/05).


I use mysql-connector-5.0.8.jar and have not had a problem in a very
long time.
I am quite sure that something was changed in the spec that altered the way the code should be written, and the old way (3.0.17) was probably automatically cleaning up while the new way (3.1.10 and above) expects the programmer to clean up.

PROBLEM IS, according to all docs I *am* doing the proper cleanup.

HERE IS MY "neutered" code:

   public static Vector listLookup(String table) {
// Connection connection = null; // connection is managed by a connection pool
       Statement statement = null;
       ResultSet resultSet = null;

       // connection is managed by a connection pool
       try {
           if(connection == null) {
               getConnection();
           }

           if(connection != null) {
               statement = connection.createStatement();
resultSet = statement.executeQuery("SELECT * FROM " + table + " ORDER BY idNumber");
               if(resultSet != null) {
                   /* process resultSet */
                   }
                   resultSet.close();
               }
               statement.close();
           }
           return /* results Vector */
       }
       catch (SQLException sqle) {
       /* debug messages */
       }
       catch (Exception e) {
       /* debug messages */
       }
       finally {
       /* debug messages */
           connection = null;
       }
       return null;
   }

NOTE: by checking debug logs, I can tell that during normal use there are NO exceptions occurring, and the finally is NOT getting called - yet the memory leak is still going on.

Cheers,

-Richard



- -chris

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to