tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Richard S. Huntrods" <huntr...@nucleus.com>
Subject Re: Would like to monitor memory use offline
Date Fri, 08 Aug 2008 16:14:00 GMT
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: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message