Re: [OT] Serious memory leak
I was wondering about one more thing... Somewhere I read that the GC can only collect objects that were instantiated with the new keyword. Does it mean the the following two String creations differ when it comes to garbage collection? 1) String myString = This is my string; 2) String myString = new String(This is my string); If the second one can only be garbage collected, this would explain my uncollectable char[] objects, because mostly I simply use the 1) version. If you say this really does count when it comes to garbage collection, I'd rewrite my code and see what happens. Thanks a lot, MB. - Original Message From: Christopher Schultz [EMAIL PROTECTED] To: Struts Users Mailing List user@struts.apache.org Sent: Wednesday, June 20, 2007 2:29:29 PM Subject: Re: [OT] Serious memory leak -BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Balazs, Balazs Michnay wrote: Thanks a lot, these changes really did help, now MySQL reports that only one connection is used all over the website. I really do appreciate your help. No problem. Another good tip is to set your connection pool size to 1 when working in development (and maybe even test). This will allow your connection pool to be exhausted any time there is a potential for deadlock (from the cp, that is). Good luck, - -chris -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGeR2o9CaO5/Lv0PARAspgAJ4yMYS06yOQ5CLE29ezyf1D5oaLhQCfWXuu GHdfh1DPw+q/1WXEByma8L4= =8bHg -END PGP SIGNATURE- - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] The fish are biting. Get more visitors on your site using Yahoo! Search Marketing. http://searchmarketing.yahoo.com/arp/sponsoredsearch_v2.php
Re: [OT] Serious memory leak
I was wondering about one more thing... Somewhere I read that the GC can only collect objects that were instantiated with the new keyword. Does it mean the the following two String creations differ when it comes to garbage collection? 1) String myString = This is my string; 2) String myString = new String(This is my string); If the second one can only be garbage collected, this would explain my uncollectable char[] objects, because mostly I simply use the 1) version. If you say this really does count when it comes to garbage collection, I'd rewrite my code and see what happens. Thanks a lot, MB. - Original Message From: Christopher Schultz [EMAIL PROTECTED] To: Struts Users Mailing List user@struts.apache.org Sent: Wednesday, June 20, 2007 2:29:29 PM Subject: Re: [OT] Serious memory leak -BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Balazs, Balazs Michnay wrote: Thanks a lot, these changes really did help, now MySQL reports that only one connection is used all over the website. I really do appreciate your help. No problem. Another good tip is to set your connection pool size to 1 when working in development (and maybe even test). This will allow your connection pool to be exhausted any time there is a potential for deadlock (from the cp, that is). Good luck, - -chris -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGeR2o9CaO5/Lv0PARAspgAJ4yMYS06yOQ5CLE29ezyf1D5oaLhQCfWXuu GHdfh1DPw+q/1WXEByma8L4= =8bHg -END PGP SIGNATURE- - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] Ready for the edge of your seat? Check out tonight's top picks on Yahoo! TV. http://tv.yahoo.com/
Re: [OT] Serious memory leak
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Balazs, Balazs Michnay wrote: Somewhere I read that the GC can only collect objects that were instantiated with the new keyword. That's an odd way of putting it. The garbage collector only works with the heap. Since in Java nearly everything is on the heap (or, rather, it appears that everything is on the heap, which is all you really need to know), the garbage collector basically cleans up everything. Does it mean the the following two String creations differ when it comes to garbage collection? 1) String myString = This is my string; 2) String myString = new String(This is my string); If the second one can only be garbage collected, this would explain my uncollectable char[] objects, because mostly I simply use the 1) version. If you say this really does count when it comes to garbage collection, I'd rewrite my code and see what happens. Well, you're introduced an odd concept into the discussion: the Java class file constant pool. When you compile a string into a class file (in this case, This is my string), the compiler puts the UTF-8 representation of it into a part of the class file itself. When line 1 of your code executes, no constructor is called... the java bytecode primitive ldc (load constant) is called which returns the String object directly. In the case of line #2, a new String object is allocated, the constant is loaded, and then the constructor String.init(String) is called. You can see this yourself by compiling this simple class and then decompiling it: $ cat StringTest.java public class StringTest { public void s1() { String s1 = This is a String; } public void s2() { String s2 = new String(This is a String); } } $ javac StringTest.java $ javap -c StringTest Compiled from StringTest.java public class StringTest extends java.lang.Object{ public StringTest(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object.init:()V 4: return public void s1(); Code: 0: ldc #2; //String This is a String 2: astore_1 3: return public void s2(); Code: 0: new #3; //class java/lang/String 3: dup 4: ldc #2; //String This is a String 6: invokespecial #4; //Method java/lang/String.init:(Ljava/lang/String;)V 9: astore_1 10: return } In the examples you have given, I'm not entirely sure what the role of the GC is when it comes to constants loaded from the constant pool. The class file format contains only the UTF-8 representation of the String, so at some point a String object /must/ be constructed in memory. You'd have to do some more research into the JVM specification to see how constant Strings are handled. You probably shouldn't have lots of string constants that contain a /lot/ of text. Maybe 400 characters or so ought to be fine (say, a semi-complex SQL query), but if you are talking about tons of text, you might want to read that kind of thing out of a file. Hope that helps, - -chris -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGf73U9CaO5/Lv0PARAvsGAJ97ZDUpN4bhtfjE1w+/sm8tNxYp6gCgtxGt CCIkTDuPsGGgMFmYfnh5nz0= =DdN4 -END PGP SIGNATURE- - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [OT] Serious memory leak
Chris, Thanks a lot, these changes really did help, now MySQL reports that only one connection is used all over the website. I really do appreciate your help. Regards, MB - Original Message From: Christopher Schultz [EMAIL PROTECTED] To: Struts Users Mailing List user@struts.apache.org Sent: Tuesday, June 19, 2007 7:10:49 PM Subject: Re: [OT] Serious memory leak Balazs, Balazs Michnay wrote: recently I found out that my memory consumption of my application is nothing compared to the memory consumption of my database server (MySQL). I'm theoretically using connection pool to save resources of my database server, but each time I make a query, I have a brand new connection. Well... are you /theoretically/ or /actually/ using a JDBC connection pool? Why doesn't PID 11 use the connection used by PID 10? There might be some errors in my code, however, it was previously reviewed and said to be correct. Do you trust the reviewer? Looking at the code you posted, I would not trust them any more :( private Statement getConnectionStatement(Connection conn) throws Exception { Context ctx = new InitialContext(); if(ctx == null ) throw new Exception(Boom - No Context); Context envCtx = (Context) ctx.lookup(java:comp/env); DataSource ds = (DataSource) envCtx.lookup(jdbc/akr_db); if (ds != null) { conn = ds.getConnection(); if(conn == null) throw new Exception(); } else throw new Exception(); return conn.createStatement(); } Do you pass an active connection to this method? If you do, then you are leaking connections every time you try to create a statement. If you are always passing null, then why do you have the Connection parameter to this method? A proper method with the above signature should be implemented like this: private Statement getConnectionStatement(Connection conn) { return conn.createStatement(); } As you can see, this method is completely worthless. It looks like your method ought to be this instead: private Connection getConnection() { Context ctx = new InitialContext(); if(ctx == null ) throw new Exception(Boom - No Context); Context envCtx = (Context) ctx.lookup(java:comp/env); // Consider checking envCtx against null, here, too // Consider making the JNDI resource name configurable // instead of hard-coding. DataSource ds = (DataSource) envCtx.lookup(jdbc/akr_db); if (ds != null) { conn = ds.getConnection(); if(conn == null) throw new Exception(); } else throw new Exception(); return conn; } The closeConnection method looks fine except for these style comments: 1. Call this method close... it closes much more than the connection. 2. Don't swallow the SQLExceptions. At least log them, but never swallow an exception! 3. Don't bother setting each reference to null. This is a waste of time, and clutters the code. Selected lines from your code: Connection conn = null; try { stmt = getConnectionStatement(conn); // Note that conn is still null here. } catch (Exception e) { System.err.println(e.getMessage()); } finally { closeConnection(conn,stmt,rst); } Conn is still null, so it will never be closed. YOU ARE LEAKING CONNECTIONS. FIX YOUR CODE. It should look like this: Connection conn = null; Statement stmt = null; // Or PreparedStatement if needed ResultSet rst = null; String query = SELECT * FROM MyTable; try { conn = getConnection(); stmt = conn.createStatement(); rst = stmt.executeQuery(query); // YOU SHOULD CHECK THIS FOR false: rst.next(); this.setTartam(rst.getString(tartam)); } catch (Exception e) { System.err.println(e.getMessage()); } finally { closeConnection(conn,stmt,rst); } Note that PreparedStatements are universally better than bare Statements when using parameterized queries (which you are not using, here). These changes should help A LOT. You are probably leaking connections all over the place. I'm curious as to why you aren't getting messages on stderr that your connection pool is empty... -chris Building a website is a piece of cake. Yahoo! Small Business gives you all the tools to get online. http://smallbusiness.yahoo.com/webhosting
Re: [OT] Serious memory leak
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Balazs, Balazs Michnay wrote: Thanks a lot, these changes really did help, now MySQL reports that only one connection is used all over the website. I really do appreciate your help. No problem. Another good tip is to set your connection pool size to 1 when working in development (and maybe even test). This will allow your connection pool to be exhausted any time there is a potential for deadlock (from the cp, that is). Good luck, - -chris -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGeR2o9CaO5/Lv0PARAspgAJ4yMYS06yOQ5CLE29ezyf1D5oaLhQCfWXuu GHdfh1DPw+q/1WXEByma8L4= =8bHg -END PGP SIGNATURE- - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [OT] Serious memory leak
user@struts.apache.org Sent: Wednesday, May 30, 2007 5:45:11 PM Subject: Re: [OT] Serious memory leak -BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Balazs, I just realized that we're talking about approximately 1MB of char[] data... what's the big deal about that? ;) Balazs Michnay wrote: Can you expand the + next to Arrays.copyOfRange to see what the rest of the stack trace is? I'm sure that a lot of things call Arrays.copyOfRange, so it's hard to determine what the problem is. Post another screenshot if you can. Sure, here it is (profiler3_expanded.JPG): http://www.inf.u-szeged.hu/~michnay/profiler/ As you can see, now there are other methods as well allocating char[] objects. It's pretty confusing and very hard to track how exactly my pages are processed by the server... at least, it is for me... :) It looks like most of those char[] objects are being allocated by Sun's HTTP client. What are you loading over HTTP? Class files? Apparently, you have some big arrays lying around: 2 * 16k bytes allocated by HttpClient.parseHTTP 39 * 16k bytes allocated by HttpClient.init (the constructor) These look like buffers. I'd be interested in seeing what is using HttpClient in your code (or Struts, I suppose). The other section (copyOfRange) has created lots of String objects. Some of them are obvious: you are reading properties from properties files and they take up memory. StringBuilder is often used by the compiler to assemble Strings combined using the + operator (for Strings). You can use it yourself, too, just like a StringBuffer. Somewhere, strings are being created (which, of course, are made-up almost entirely of char[] objects). I'll try to factor out the JNDI parts. Should I factor out the creation of statement and result objects as well, or only the connection should be factored out? I would only do the Connection. What else would you do? Have a method like this? public Statement createStatement(Connection conn, String sql) { return conn.createStatement(sql); } ??! That's a pretty worthless method. Should I create another method to free up the resources? I have done that myself: protected void close(Connection conn, Statement s, ResultSet r) { /// this guy is protected because it's in a superclass // for each object, check for null, try { close } catch { log } } In terms of design, I would write that method to return a List of application-specific objects instead of maintaining two separate (untyped) lists that just happen to be related. It is a much more understandable design and yields much more readable code. It will also simplify your JSP loop, etc. What do you mean by List of application-specific objects? Is it a multi-dimensional ArrayList object? I'm very interested in creating well-readable and well-understandable code, so some samples would be appreciated :) (sorry, I'm not very experienced in Java) I know how you feel. We used to have a programmer who didn't realize he could create his own types. Stop thinking that everything has to be a String hidden inside a baffling maze of nested Lists and Maps. If you have an entity that you like to think of as a person (for example), then you can represent this data in at least two ways: 1. Use a List of Strings where the index of the string has meaning, but only in your head. Something like this: ArrayList person = new ArrayList(); person.add(Chris); // 0 == first name person.add(Schultz); // 1 == last name person.add(Male);// 2 == gender ArrayList people = new ArrayList(); people.add(person); // etc. 2. Use an object you define yourself. public class Person { String firstName; String lastName; } ArrayList people = new ArrayList(); people.add(new Person(Chris, Schultz, Male)); // etc. If you use solution #1, you'll never know if the ArrayList you're getting is an array of String representing person entities or a list of strings representing Account entities, or whatever. You basically have to cross your fingers and hope that the documentation for the method is correct. If you use #2, you can use the compiler and runtime to enforce your notion of what is what: That list /does/ contain Person objects. You seriously simplify your code and rarely get confused. You save a lot of memory, too, since ArrayLists have overhead that you don't need if you use your own objects. These things are typically called business objects, but only when they map into domain-specific entities (meaning that they represent real concepts in the language of the problem... like Account for financial software, or PurchaseOrder for an ordering system). You are free to create other types that are useful to you even if they are not business objects per se any time you find yourself stuffing things like bare Strings into Maps or Lists, ask yourself if you shouldn't be defining your own type (or class... or object... or whatever you want to call it). Do you see
Re: [OT] Serious memory leak
I forgot to include the link to the image. Here it is: http://www.inf.u-szeged.hu/~michnay/db/db_connections.jpg - Original Message From: Balazs Michnay [EMAIL PROTECTED] To: Struts Users Mailing List user@struts.apache.org Sent: Tuesday, June 19, 2007 2:16:06 PM Subject: Re: [OT] Serious memory leak Thanks for your reply on the memory leak issue Well, recently I found out that my memory consumption of my application is nothing compared to the memory consumption of my database server (MySQL). I'm theoretically using connection pool to save resources of my database server, but each time I make a query, I have a brand new connection. Please take a look at the following image that shows the state of my user connection. I have lots of connections, however theses are only different queries from the same web application. Why doesn't PID 11 use the connection used by PID 10? There might be some errors in my code, however, it was previously reviewed and said to be correct. Please take a look at the following source... I have 2 methods related to my connection pool: ---GETTING CONNECTION --- private Statement getConnectionStatement(Connection conn) throws Exception { Context ctx = new InitialContext(); if(ctx == null ) throw new Exception(Boom - No Context); Context envCtx = (Context) ctx.lookup(java:comp/env); DataSource ds = (DataSource) envCtx.lookup(jdbc/akr_db); if (ds != null) { conn = ds.getConnection(); if(conn == null) throw new Exception(); } else throw new Exception(); return conn.createStatement(); } - ---CLOSING CONNECTION --- private void closeConnection(Connection conn, Statement stmt, ResultSet rst) { // Always make sure result sets and statements are closed, // and the connection is returned to the pool if (stmt != null) { try { stmt.close(); } catch (SQLException e) { ; } stmt = null; } if (conn != null) { try { conn.close(); } catch (SQLException e) { ; } conn = null; } if (rst != null) { try { rst.close(); } catch (SQLException e) { ; } rst = null; } } - ---USING CONNECTION POOL IN A METHOD- Connection conn = null; Statement stmt = null; // Or PreparedStatement if needed ResultSet rst = null; String query = SELECT * FROM MyTable; try { stmt = getConnectionStatement(conn); rst = stmt.executeQuery(query); rst.next(); this.setTartam(rst.getString(tartam)); } catch (Exception e) { System.err.println(e.getMessage()); } finally { closeConnection(conn,stmt,rst); } - Furthermore, I have a context.xml with the following content: Context path=/SZTGKR ResourceLink global=jdbc/akr_db name=jdbc/akr_db type=javax.sql.DataSource/ /Context - In the web.xml I have an entry related to my db connection: resource-ref description DB Connection Pooling/description res-ref-name jdbc/akr_db/res-ref-name res-type javax.sql.DataSource/res-type res-auth Container/res-auth /resource-ref -- GlobalNamingResources Environment name=simpleValue type=java.lang.Integer value=30/ Resource auth=Container name=jdbc/akr_db type=javax.sql.DataSource maxActive=100 maxIdle=30 username=balazs maxWait=1 driverClassName=com.mysql.jdbc.Driver removeAbandoned=true password=12345 url=jdbc:mysql://localhost:3306/akr_db removeAbandonedTimeout=30/ Resource auth=Container description=User database that can be updated and saved name=UserDatabase type=org.apache.catalina.UserDatabase pathname=conf/tomcat-users.xml factory=org.apache.catalina.users.MemoryUserDatabaseFactory/ /GlobalNamingResources
Re: [OT] Serious memory leak
Balazs, Balazs Michnay wrote: recently I found out that my memory consumption of my application is nothing compared to the memory consumption of my database server (MySQL). I'm theoretically using connection pool to save resources of my database server, but each time I make a query, I have a brand new connection. Well... are you /theoretically/ or /actually/ using a JDBC connection pool? Why doesn't PID 11 use the connection used by PID 10? There might be some errors in my code, however, it was previously reviewed and said to be correct. Do you trust the reviewer? Looking at the code you posted, I would not trust them any more :( private Statement getConnectionStatement(Connection conn) throws Exception { Context ctx = new InitialContext(); if(ctx == null ) throw new Exception(Boom - No Context); Context envCtx = (Context) ctx.lookup(java:comp/env); DataSource ds = (DataSource) envCtx.lookup(jdbc/akr_db); if (ds != null) { conn = ds.getConnection(); if(conn == null) throw new Exception(); } else throw new Exception(); return conn.createStatement(); } Do you pass an active connection to this method? If you do, then you are leaking connections every time you try to create a statement. If you are always passing null, then why do you have the Connection parameter to this method? A proper method with the above signature should be implemented like this: private Statement getConnectionStatement(Connection conn) { return conn.createStatement(); } As you can see, this method is completely worthless. It looks like your method ought to be this instead: private Connection getConnection() { Context ctx = new InitialContext(); if(ctx == null ) throw new Exception(Boom - No Context); Context envCtx = (Context) ctx.lookup(java:comp/env); // Consider checking envCtx against null, here, too // Consider making the JNDI resource name configurable // instead of hard-coding. DataSource ds = (DataSource) envCtx.lookup(jdbc/akr_db); if (ds != null) { conn = ds.getConnection(); if(conn == null) throw new Exception(); } else throw new Exception(); return conn; } The closeConnection method looks fine except for these style comments: 1. Call this method close... it closes much more than the connection. 2. Don't swallow the SQLExceptions. At least log them, but never swallow an exception! 3. Don't bother setting each reference to null. This is a waste of time, and clutters the code. Selected lines from your code: Connection conn = null; try { stmt = getConnectionStatement(conn); // Note that conn is still null here. } catch (Exception e) { System.err.println(e.getMessage()); } finally { closeConnection(conn,stmt,rst); } Conn is still null, so it will never be closed. YOU ARE LEAKING CONNECTIONS. FIX YOUR CODE. It should look like this: Connection conn = null; Statement stmt = null; // Or PreparedStatement if needed ResultSet rst = null; String query = SELECT * FROM MyTable; try { conn = getConnection(); stmt = conn.createStatement(); rst = stmt.executeQuery(query); // YOU SHOULD CHECK THIS FOR false: rst.next(); this.setTartam(rst.getString(tartam)); } catch (Exception e) { System.err.println(e.getMessage()); } finally { closeConnection(conn,stmt,rst); } Note that PreparedStatements are universally better than bare Statements when using parameterized queries (which you are not using, here). These changes should help A LOT. You are probably leaking connections all over the place. I'm curious as to why you aren't getting messages on stderr that your connection pool is empty... -chris signature.asc Description: OpenPGP digital signature
Re: [OT] Serious memory leak
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Balazs, I just realized that we're talking about approximately 1MB of char[] data... what's the big deal about that? ;) Balazs Michnay wrote: Can you expand the + next to Arrays.copyOfRange to see what the rest of the stack trace is? I'm sure that a lot of things call Arrays.copyOfRange, so it's hard to determine what the problem is. Post another screenshot if you can. Sure, here it is (profiler3_expanded.JPG): http://www.inf.u-szeged.hu/~michnay/profiler/ As you can see, now there are other methods as well allocating char[] objects. It's pretty confusing and very hard to track how exactly my pages are processed by the server... at least, it is for me... :) It looks like most of those char[] objects are being allocated by Sun's HTTP client. What are you loading over HTTP? Class files? Apparently, you have some big arrays lying around: 2 * 16k bytes allocated by HttpClient.parseHTTP 39 * 16k bytes allocated by HttpClient.init (the constructor) These look like buffers. I'd be interested in seeing what is using HttpClient in your code (or Struts, I suppose). The other section (copyOfRange) has created lots of String objects. Some of them are obvious: you are reading properties from properties files and they take up memory. StringBuilder is often used by the compiler to assemble Strings combined using the + operator (for Strings). You can use it yourself, too, just like a StringBuffer. Somewhere, strings are being created (which, of course, are made-up almost entirely of char[] objects). I'll try to factor out the JNDI parts. Should I factor out the creation of statement and result objects as well, or only the connection should be factored out? I would only do the Connection. What else would you do? Have a method like this? public Statement createStatement(Connection conn, String sql) { return conn.createStatement(sql); } ??! That's a pretty worthless method. Should I create another method to free up the resources? I have done that myself: protected void close(Connection conn, Statement s, ResultSet r) { /// this guy is protected because it's in a superclass // for each object, check for null, try { close } catch { log } } In terms of design, I would write that method to return a List of application-specific objects instead of maintaining two separate (untyped) lists that just happen to be related. It is a much more understandable design and yields much more readable code. It will also simplify your JSP loop, etc. What do you mean by List of application-specific objects? Is it a multi-dimensional ArrayList object? I'm very interested in creating well-readable and well-understandable code, so some samples would be appreciated :) (sorry, I'm not very experienced in Java) I know how you feel. We used to have a programmer who didn't realize he could create his own types. Stop thinking that everything has to be a String hidden inside a baffling maze of nested Lists and Maps. If you have an entity that you like to think of as a person (for example), then you can represent this data in at least two ways: 1. Use a List of Strings where the index of the string has meaning, but only in your head. Something like this: ArrayList person = new ArrayList(); person.add(Chris); // 0 == first name person.add(Schultz); // 1 == last name person.add(Male);// 2 == gender ArrayList people = new ArrayList(); people.add(person); // etc. 2. Use an object you define yourself. public class Person { String firstName; String lastName; } ArrayList people = new ArrayList(); people.add(new Person(Chris, Schultz, Male)); // etc. If you use solution #1, you'll never know if the ArrayList you're getting is an array of String representing person entities or a list of strings representing Account entities, or whatever. You basically have to cross your fingers and hope that the documentation for the method is correct. If you use #2, you can use the compiler and runtime to enforce your notion of what is what: That list /does/ contain Person objects. You seriously simplify your code and rarely get confused. You save a lot of memory, too, since ArrayLists have overhead that you don't need if you use your own objects. These things are typically called business objects, but only when they map into domain-specific entities (meaning that they represent real concepts in the language of the problem... like Account for financial software, or PurchaseOrder for an ordering system). You are free to create other types that are useful to you even if they are not business objects per se any time you find yourself stuffing things like bare Strings into Maps or Lists, ask yourself if you shouldn't be defining your own type (or class... or object... or whatever you want to call it). Do you see any place where objects could not be freed-up? Where? I'll show you. Please take a look at
Re: [OT] Serious memory leak
Maybe you're creating a new session with each request. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]