Re: Memory Usage and Garbage Collection
Hi Steve, The real decision you need to make is how common are the common parts of your JSPs, and how much content is within the JSPs. If most of your JSPs are simply blocks of content surrounded by the same boiler plate JSP code, then perhaps it is worth while to make those JSPs a single JSP that then loads the different content at runtime based upon the request. But the real consideration is simply the amount of content that you're delivering within the JSPs. Consider this: If you have 500 JSP's that each have 20K of text (which is quite a bit of text if you think about it), then that's only 20MB of memory for the content. The calculation is 500 files x 20,000 characters x 2 for unicode (unicode characters, which Java uses, are 2 bytes). So, using brute force, back-of-napkin calculations, 512MB of memory would store 25000 of those documents. Also, if your document count is mostly static from day to day, i.e. you aren't adding large numbers of new documents each day, then you can easily pre-compute your overall memory burden simply for the documents, and scale appropriately. So, I doubt the JSPs alone are causing your memory problems, it's probably something else. Hope this was helpful, Regards, Will Hartung ([EMAIL PROTECTED]) - Original Message - From: Turoff, Steve [EMAIL PROTECTED] To: Will Hartung [EMAIL PROTECTED] Sent: Tuesday, January 14, 2003 10:07 AM Subject: RE: Memory Usage and Garbage Collection Will, I too am experiencing memory problems and I think your explanation below might apply to me. I'm using Tomcat 4.1 on RedHat Linux. Over the course of a few days, I notice, (using top) that the amount of physical memory used by the java processes continually increases until it exceeds the maximum that I've set (-Xmx512m) and then will generate an java.lang.OutOfMemoryError in $CATALINA_HOME/logs/localhost_log.-MM-DD.txt. I believe the problem is that my JSPs are dynamic, but I'm not sure exactly what differentiates a static JSP from a dynamic JSP. -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Will, I too am experiencing memory problems and I think your explanation below might apply to me. I'm using Tomcat 4.1 on RedHat Linux. Over the course of a few days, I notice, (using top) that the amount of physical memory used by the java processes continually increases until it hits the maximum that I've set (-Xmx512m) and then will generate an outOfMemory error. I believe the problem is that my JSPs are dynamic, but I'm not sure exactly what differentiates a static JSP from a dynamic JSP. I have several hundred JSPs - each one looks like: !-- BEGIN SAMPLE PAGE -- jsp:useBean id=thisPage class=PHN.PHNPage scope=session / jsp:setProperty name=thisPage property=section value=foo / %@ include file=/templates/header.jsp % I am body content. Some pages use the following java: a href=/a.pdfDocument a/a (PDF file - %= new File(/a.pdf).length()/1024 % %@ include file=/templates/footer.jsp % !-- END SAMPLE PAGE -- header.jsp looks something like this: !-- BEGIN HEADER.JSP -- % String host = http://; + request.getServerName(); String requestURI = request.getRequestURI(); String pageType = request.getParameter(pageType); String section = thisPage.getSection(); % A bunch of HTML % if (section.equals(foo)) { % %@ include file=/nav/foo.jsp % % } % !-- END HEADER.JSP -- footer.jsp is similar. So are my JSPs dynamic? If so, can I solve my memory problems by switching them to XML docs and using a single JSP page (along with XSLT) to render the pages? Thanks much for your help. Steve -Original Message- From: Will Hartung [mailto:[EMAIL PROTECTED]] Sent: Friday, January 03, 2003 4:54 PM To: Tomcat Users List Subject: Re: Memory Usage and Garbage Collection From: Brandon Cruz [EMAIL PROTECTED] Sent: Friday, January 03, 2003 2:23 PM Subject: RE: Memory Usage and Garbage Collection 1)For every single request to a servlet or JSP page, a new instance of that class is created? For example, if there is one JSP page and ten people access that one page over the course of a day, 10 separate instances of the same class are created and will never be gc'd until the webapp or tomcat is restarted? No no no. Ever so confusing. Here's the rub. First, consider that JSP == Servlet. Second, Servlet == Java Class. When a request comes in for a Servlet, the Servlet class is loaded. Then (assuming we're not using a Single Threaded Model Servlet), a new instance of that Servlet is created to handle the request. These instances of the Servlet will inevitably be GC'd in time. However, what will NOT be GC'd is the CLASS of the Servlet. Once the class is loaded, the class stays around until restart. This is because the ClassLoader for the Servlet hangs on to it. For most applications this is not a problem, as Servlets are roughly equivalent to CGI programs. However, where Servlets are similar to CGI programs, some are equating JSPs with HTML files (or, perhaps better, SHTML files). Most normal sites would have very few CGI programs, but may have loads of HTML or SHTML files. But, since JSPs are actually Servlets in cheap clothing, the JSP == HTML file is not a valid assumption to make. Whereas Servlets are usually mostly just logic, JSPs tend to be mostly content. So, when the server loads the Servlet class generated by the JSP, it loads and caches more content than logic. If Apache remembered and cached every HTML file that went through it, you'd end up potentially caching your entire web tree in RAM. If you happen to have enough RAM to support this, it's not a problem. But if your content is growing every day, and old data doesn't go away, you will eventially run out of RAM and Bad Things will happen. Our site has ~1200 JSPs but all told they only add up to about 6MB, and they're static. So, if all of those managed to get sucked into RAM, the space they would take wouldn't even make a 256MB Tomcat instance blink, so it's not a problem for us. But another fella was generating dynamic JSPs, and would thereby eventually starve out his heap because Tomcat wasn't expiring Servlets. The real question is whether JSPs should be considered Different Enough from normal Servlets to warrant adding code to scavenge them. Regards, Will Hartung ([EMAIL PROTECTED]) -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Thanks for that explanation, But i was just curious to know if weakmaps or similar gc interacting cache be used to keep the mem size in control. Servers with high mem size would continue to keep the cache of jsp's for performance whereas the ones with lesser mem size would still not give the outofmemory error. saurabh [EMAIL PROTECTED] 01/04/03 01:12AM On Fri, 3 Jan 2003, Saurabh Arora wrote: Date: Fri, 03 Jan 2003 02:33:17 -0700 From: Saurabh Arora [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED] To: [EMAIL PROTECTED] Subject: RE: Memory Usage and Garbage Collection Just wanted to know, does the current implementation of tomcat 4.1.18 also has the same problem of keeping the jsp's in memory. or it was only present in 4.0.4 It's not a *problem* -- it's a *feature* :-). This is one of the keys to maintaining good performance on repeatedly requested pages. Yes, Tomcat 4.1.x maintains a reference to every JSP page that has ever been requested (same as every servlet that has ever been requested) until that webapp is reloaded or removed, or you shut down Tomcat. Given this, designing webapps where you auto-generate hundreds of different JSP pages (which was the choice of the originator of this message thread) is not what you really want to do. Instead, you'd want to use a single JSP page for each basic *style* of output (essentially the JSP page would be a formatting template) that pulls in the unique information for a particular report (from the database, from XML, or whatever) dynamically. Then, a given webpp would likely have 5-10 JSP pages, instead of hundreds. Just as an example, assume that your application back-end gave you the data you need in some XML format, and you want to offer your user the chance to format this data in ten different ways. If you create an XSLT stylesheet to transform the data for each of the ten formats, you can do this all with a *single* JSP page that takes an XML data source and an XSLT stylesheet, applies the transformation, and renders the result. (JSTL has a tag that will do all the grunt work for you.) If you really really want to auto-generate all the reports ahead of time, go ahead and generate static HTML pages -- don't waste your time generating JSP that then has to get compiled, loaded, and executed. As a side benefit, the output will get served a little faster because there is less overhead in serving static files. If you really really really want to generate hundreds of JSP pages, then plan on buying enough memory to hold them all and be done with it. Fortunately, this is not usually a break the bank decision (I just upgraded my development PC to a gigabyte of memory for less than $100 :-). If you really really really really want to generate hundreds of JSP pages, and don't (or can't) afford the memory to hold them all, you only have yourself to blame for the results. saurabh Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: Memory Usage and Garbage Collection
So the instance, and it's string, can still be GC'd, right? Nope. There is still a live reference to each OtherObject instance sitting in the static HashMap cache. Therefore, this instance cannot be GC'd, even though *you* have released your own reference to it. And, if the OtherObject class is loaded from Tomcat's common/lib directory (for example), there is no way to ***ever*** GC this instance, because the public API of the OtherObject class doesn't offer any way to clear the cache. Wouldn't it be the responsibility of the Factory to worry about releasing objects to the GC? I mean, if it implements caching, it should have some sort of policy when an instantiated (and, thus, cached) object is a candidate for GC. Obvious guidelines are: - if it is not used - if it has last been used less recently than some limit One can also think of a non-linear function, which checks the available memory or has it's internal memory limit. Nix. -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Hi Craig, please see intermixed. On 2 Jan 2003 at 18:18, Craig R. McClanahan wrote: Instances can be garbage collected IF AND ONLY IF there are no live references to that object in a static/instance/local variable of some other object that is also in memory. Only instances that are no longer referenced from other object instances can be recycled. Please consider the following service() or doGet() or so of a servlet: public void service(ServletRequest request, ServletResponse response) throws IOException { OtherObject otherObject = new OtherObject(); otherObject.doThisAndThat(request, response); } Do I have to place the following otherObject = null; before the end of service(). Doesn't otherObject be gc-ed otherwise? I've never done this. What about the object instances, which otherObject.doThisAndThat() creates? So far I've thought there are no live references if otherObject gets gc-ed. In the case at hand, Tomcat (obviously) has references to all the servlets that it has loaded. Therefore, those servlet instances cannot be garbage collected. Furthermore, any object that is referenced by static or instance variables of your servlet class can *also* not be garbage collected, because live references still exist. Same thing for session attributes. OK, this is obvious. Andreas deleted the latter parts... -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Just wanted to know, does the current implementation of tomcat 4.1.18 also has the same problem of keeping the jsp's in memory. or it was only present in 4.0.4 saurabh [EMAIL PROTECTED] 01/03/03 02:26PM Hi Craig, please see intermixed. On 2 Jan 2003 at 18:18, Craig R. McClanahan wrote: Instances can be garbage collected IF AND ONLY IF there are no live references to that object in a static/instance/local variable of some other object that is also in memory. Only instances that are no longer referenced from other object instances can be recycled. Please consider the following service() or doGet() or so of a servlet: public void service(ServletRequest request, ServletResponse response) throws IOException { OtherObject otherObject = new OtherObject(); otherObject.doThisAndThat(request, response); } Do I have to place the following otherObject = null; before the end of service(). Doesn't otherObject be gc-ed otherwise? I've never done this. What about the object instances, which otherObject.doThisAndThat() creates? So far I've thought there are no live references if otherObject gets gc-ed. In the case at hand, Tomcat (obviously) has references to all the servlets that it has loaded. Therefore, those servlet instances cannot be garbage collected. Furthermore, any object that is referenced by static or instance variables of your servlet class can *also* not be garbage collected, because live references still exist. Same thing for session attributes. OK, this is obvious. Andreas deleted the latter parts... -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Hi, There's clearly some misconceptions on the topic of garbage collection ;) These questions come up very often it seems, on this list and others. Please consider the following service() or doGet() or so of a servlet: public void service(ServletRequest request, ServletResponse response) throws IOException { OtherObject otherObject = new OtherObject(); otherObject.doThisAndThat(request, response); } Do I have to place the following otherObject = null; before the end of service(). Doesn't otherObject be gc-ed otherwise? I've never done this. You don't have to do this. The otherObject's reference count is increase by one when you assign it. When the method (service() above) returns, the reference count for otherObject is reduced by one. If the reference count is zero, otherObject can be garbage collected. What about the object instances, which otherObject.doThisAndThat() creates? So far I've thought there are no live references if otherObject gets gc-ed. If otherObject creates local objects, they'll be GCed. If it modifies static objects, those objects stay in a different place anyways and don't get GCed when otherObject does. Back to what Craig mentioned earlier: earlier in the Java life time, classes could get GCed themselves. That really earns you very little, so it was removed. Nowadays demands on classloaders and their hierarchies can get very complicated, so re-introducing class GC would be difficult anyways. A JSP is compiled into a servlet and then loaded into memory. Its bytecode is present only once, and takes up relatively little space (usually). You won't gain much from destroying that bytecode and de-allocating its memory. Same thing for normal servlets obviouisly. What you need to do is tune your garbage collection. With some exceptions, full GCs shouldn't run all the time. Depending on your collector, partial GCs can run all the time. You'd expect that from incremental and concurrent collectors. If you're running on multiple CPUs and have a parallel collector but only one System.out log, you'd expect to see GC output there nearly all the time. So you should start playing with your heap (-Xmx), new generation size and ration (XX:NewSize, XX:MaxNewSize, XX:NewRatio), collector policy (-Xincgc, -Xconcgc, XX:UseParNewGC, etc.) and other parameters to see which gives you the best behavior. Don't -Xmx over the physical RAM size. See the VM options page at: http://java.sun.com/docs/hotspot/VMOptions.html One principle to keep in mind is that memory is cheap, or at least considered cheap when it comes to GC performance tuning. The java heap is greedy overall, and this is intended to increaser performance. That's why it won't de-allocate space (and never return space to the OS) until necessary with the default mark/sweep collector. Make sure to record your verbose:gc output between runs so that you can compare behavior. This is not typically easy to tell by instinctive feel. Yoav Shapira Millennium ChemInformatics -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Hi thank you, your reply calms me down again. I guess I got a bit confused by the preceding discussion. Andreas On 3 Jan 2003 at 8:59, Shapira, Yoav wrote: Hi, There's clearly some misconceptions on the topic of garbage collection ;) These questions come up very often it seems, on this list and others. Please consider the following service() or doGet() or so of a servlet: public void service(ServletRequest request, ServletResponse response) throws IOException { OtherObject otherObject = new OtherObject(); otherObject.doThisAndThat(request, response); } Do I have to place the following otherObject = null; before the end of service(). Doesn't otherObject be gc-ed otherwise? I've never done this. You don't have to do this. The otherObject's reference count is increase by one when you assign it. When the method (service() above) returns, the reference count for otherObject is reduced by one. If the reference count is zero, otherObject can be garbage collected. What about the object instances, which otherObject.doThisAndThat() creates? So far I've thought there are no live references if otherObject gets gc-ed. If otherObject creates local objects, they'll be GCed. If it modifies static objects, those objects stay in a different place anyways and don't get GCed when otherObject does. Back to what Craig mentioned earlier: earlier in the Java life time, classes could get GCed themselves. That really earns you very little, so it was removed. Nowadays demands on classloaders and their hierarchies can get very complicated, so re-introducing class GC would be difficult anyways. A JSP is compiled into a servlet and then loaded into memory. Its bytecode is present only once, and takes up relatively little space (usually). You won't gain much from destroying that bytecode and de-allocating its memory. Same thing for normal servlets obviouisly. What you need to do is tune your garbage collection. With some exceptions, full GCs shouldn't run all the time. Depending on your collector, partial GCs can run all the time. You'd expect that from incremental and concurrent collectors. If you're running on multiple CPUs and have a parallel collector but only one System.out log, you'd expect to see GC output there nearly all the time. So you should start playing with your heap (-Xmx), new generation size and ration (XX:NewSize, XX:MaxNewSize, XX:NewRatio), collector policy (-Xincgc, -Xconcgc, XX:UseParNewGC, etc.) and other parameters to see which gives you the best behavior. Don't -Xmx over the physical RAM size. See the VM options page at: http://java.sun.com/docs/hotspot/VMOptions.html One principle to keep in mind is that memory is cheap, or at least considered cheap when it comes to GC performance tuning. The java heap is greedy overall, and this is intended to increaser performance. That's why it won't de-allocate space (and never return space to the OS) until necessary with the default mark/sweep collector. Make sure to record your verbose:gc output between runs so that you can compare behavior. This is not typically easy to tell by instinctive feel. Yoav Shapira Millennium ChemInformatics -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
On Fri, 3 Jan 2003, Andreas Probst wrote: Hi Craig, please see intermixed. On 2 Jan 2003 at 18:18, Craig R. McClanahan wrote: Instances can be garbage collected IF AND ONLY IF there are no live references to that object in a static/instance/local variable of some other object that is also in memory. Only instances that are no longer referenced from other object instances can be recycled. Please consider the following service() or doGet() or so of a servlet: public void service(ServletRequest request, ServletResponse response) throws IOException { OtherObject otherObject = new OtherObject(); otherObject.doThisAndThat(request, response); } Do I have to place the following otherObject = null; before the end of service(). Doesn't otherObject be gc-ed otherwise? I've never done this. The otherObject reference goes away as soon as the service() method returns, so you don't have to actually release it yourself. HOWEVER, you also need to understand what the constructor of this class did, and what the doThisAndThat() method did -- it's still possible for that class to cause memory leaks which you don't know anything about, or possibly can't do anything about. What about the object instances, which otherObject.doThisAndThat() creates? So far I've thought there are no live references if otherObject gets gc-ed. Let's look at a simple case and a complex case: SIMPLE CASE: OtherObject has a single instance variable that is initialized to a String: public class OtherObject { private String id; public OtherObject(String id) { this.id = id; } public String getId() { return (this.id); } } In this case, the only reference to the String pointed at by id is in this instance of OtherObject. Therefore, when you release your reference to the OtherObject instance and the id string that was passed in (because the service() method ended), both the OtherObject instance and the foo String instance are available for GC. COMPLEX CASE: OtherObject is a little trickier in its initialization -- it provides a factory pattern method that creates at most one instance of OtherObject for a particular identifier string. (This is a *very* common design pattern -- in fact, Tomcat implements something sort of like this to ensure that there is at most one instance of each servlet class.) public class OtherObject { // Private constructor -- use the factory method instead private OtherObject(String id) { this.id = id; } // Private instance variable -- one per instance private String id; // Public getter for the id property public String getId() { return (this.id); } // Static cache of previously created instances private static HashMap cache = new HashMap(); // Factory method for creating OtherObject instances that // guarantees to create only one for a particular id string public static OtherObject getOtherObject(String id) { synchronized (cache) { OtherObject instance = (OtherObject) cache.get(id); if (instance == null) { instance = new OtherObject(id); cache.put(id, instance); } return (instance); } } } To use the factory method, you'd say something like this: OtherObject otherObject = OtherObject.getOtherObject(idstring); instead of: OtherObject otherObject = new OtherObject(idstring); and, no matter how many times you call this with the same parameter value, you'd get the same instance back (basically a singleton pattern with lazy instantiation). Now, your otherObject reference still goes away at the end of the service() method, right? Yep. So the instance, and it's string, can still be GC'd, right? Nope. There is still a live reference to each OtherObject instance sitting in the static HashMap cache. Therefore, this instance cannot be GC'd, even though *you* have released your own reference to it. And, if the OtherObject class is loaded from Tomcat's common/lib directory (for example), there is no way to ***ever*** GC this instance, because the public API of the OtherObject class doesn't offer any way to clear the cache. Note also that there is nothing that your servlet can do about this -- you can't even know if its happening without consulting the documentation and/or the source code for the classes you are calling. But the code above will cause a slowly increasing consumption of memory over time (assuming that you're asking for different id values), even though *you* are not maintaining any live references to these objects. Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
On Fri, 3 Jan 2003, Saurabh Arora wrote: Date: Fri, 03 Jan 2003 02:33:17 -0700 From: Saurabh Arora [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED] To: [EMAIL PROTECTED] Subject: RE: Memory Usage and Garbage Collection Just wanted to know, does the current implementation of tomcat 4.1.18 also has the same problem of keeping the jsp's in memory. or it was only present in 4.0.4 It's not a *problem* -- it's a *feature* :-). This is one of the keys to maintaining good performance on repeatedly requested pages. Yes, Tomcat 4.1.x maintains a reference to every JSP page that has ever been requested (same as every servlet that has ever been requested) until that webapp is reloaded or removed, or you shut down Tomcat. Given this, designing webapps where you auto-generate hundreds of different JSP pages (which was the choice of the originator of this message thread) is not what you really want to do. Instead, you'd want to use a single JSP page for each basic *style* of output (essentially the JSP page would be a formatting template) that pulls in the unique information for a particular report (from the database, from XML, or whatever) dynamically. Then, a given webpp would likely have 5-10 JSP pages, instead of hundreds. Just as an example, assume that your application back-end gave you the data you need in some XML format, and you want to offer your user the chance to format this data in ten different ways. If you create an XSLT stylesheet to transform the data for each of the ten formats, you can do this all with a *single* JSP page that takes an XML data source and an XSLT stylesheet, applies the transformation, and renders the result. (JSTL has a tag that will do all the grunt work for you.) If you really really want to auto-generate all the reports ahead of time, go ahead and generate static HTML pages -- don't waste your time generating JSP that then has to get compiled, loaded, and executed. As a side benefit, the output will get served a little faster because there is less overhead in serving static files. If you really really really want to generate hundreds of JSP pages, then plan on buying enough memory to hold them all and be done with it. Fortunately, this is not usually a break the bank decision (I just upgraded my development PC to a gigabyte of memory for less than $100 :-). If you really really really really want to generate hundreds of JSP pages, and don't (or can't) afford the memory to hold them all, you only have yourself to blame for the results. saurabh Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Hi Craig, thank you very much for this complete explanation. That's perfectly understandable and the GC-behaviour which I had expected before. I must have understood something wrong in this thread's discussion, which went on yesterday. Again, thank you very much for your helpful responses (not only this one). Andreas On 3 Jan 2003 at 11:31, Craig R. McClanahan wrote: On Fri, 3 Jan 2003, Andreas Probst wrote: Hi Craig, please see intermixed. On 2 Jan 2003 at 18:18, Craig R. McClanahan wrote: Instances can be garbage collected IF AND ONLY IF there are no live references to that object in a static/instance/local variable of some other object that is also in memory. Only instances that are no longer referenced from other object instances can be recycled. Please consider the following service() or doGet() or so of a servlet: public void service(ServletRequest request, ServletResponse response) throws IOException { OtherObject otherObject = new OtherObject(); otherObject.doThisAndThat(request, response); } Do I have to place the following otherObject = null; before the end of service(). Doesn't otherObject be gc-ed otherwise? I've never done this. The otherObject reference goes away as soon as the service() method returns, so you don't have to actually release it yourself. HOWEVER, you also need to understand what the constructor of this class did, and what the doThisAndThat() method did -- it's still possible for that class to cause memory leaks which you don't know anything about, or possibly can't do anything about. What about the object instances, which otherObject.doThisAndThat() creates? So far I've thought there are no live references if otherObject gets gc-ed. Let's look at a simple case and a complex case: SIMPLE CASE: OtherObject has a single instance variable that is initialized to a String: public class OtherObject { private String id; public OtherObject(String id) { this.id = id; } public String getId() { return (this.id); } } In this case, the only reference to the String pointed at by id is in this instance of OtherObject. Therefore, when you release your reference to the OtherObject instance and the id string that was passed in (because the service() method ended), both the OtherObject instance and the foo String instance are available for GC. COMPLEX CASE: OtherObject is a little trickier in its initialization -- it provides a factory pattern method that creates at most one instance of OtherObject for a particular identifier string. (This is a *very* common design pattern -- in fact, Tomcat implements something sort of like this to ensure that there is at most one instance of each servlet class.) public class OtherObject { // Private constructor -- use the factory method instead private OtherObject(String id) { this.id = id; } // Private instance variable -- one per instance private String id; // Public getter for the id property public String getId() { return (this.id); } // Static cache of previously created instances private static HashMap cache = new HashMap(); // Factory method for creating OtherObject instances that // guarantees to create only one for a particular id string public static OtherObject getOtherObject(String id) { synchronized (cache) { OtherObject instance = (OtherObject) cache.get(id); if (instance == null) { instance = new OtherObject(id); cache.put(id, instance); } return (instance); } } } To use the factory method, you'd say something like this: OtherObject otherObject = OtherObject.getOtherObject(idstring); instead of: OtherObject otherObject = new OtherObject(idstring); and, no matter how many times you call this with the same parameter value, you'd get the same instance back (basically a singleton pattern with lazy instantiation). Now, your otherObject reference still goes away at the end of the service() method, right? Yep. So the instance, and it's string, can still be GC'd, right? Nope. There is still a live reference to each OtherObject instance sitting in the static HashMap cache. Therefore, this instance cannot be GC'd, even though *you* have released your own reference to it. And, if the OtherObject class is loaded from Tomcat's common/lib directory (for example), there is no way to ***ever*** GC this instance, because the public API of the OtherObject class doesn't offer any way to clear the cache. Note also that there is nothing that your servlet can do about this -- you can't even know if its happening without consulting the documentation and/or the source code for the classes you are calling. But the code above will cause a slowly increasing
RE: Memory Usage and Garbage Collection
Craig, From what you have been saying... 1)For every single request to a servlet or JSP page, a new instance of that class is created? For example, if there is one JSP page and ten people access that one page over the course of a day, 10 separate instances of the same class are created and will never be gc'd until the webapp or tomcat is restarted? 2)If this is true, it looks to me like any java application in the world eventually has to be restarted as more and more people access it. Buying more memory would prolong the time to restart the application, but eventually all the instances created will take up all the available RAM. Is this correct? Brandon -Original Message- From: Craig R. McClanahan [mailto:[EMAIL PROTECTED]] Sent: Friday, January 03, 2003 1:43 PM To: Tomcat Users List Subject: RE: Memory Usage and Garbage Collection On Fri, 3 Jan 2003, Saurabh Arora wrote: Date: Fri, 03 Jan 2003 02:33:17 -0700 From: Saurabh Arora [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED] To: [EMAIL PROTECTED] Subject: RE: Memory Usage and Garbage Collection Just wanted to know, does the current implementation of tomcat 4.1.18 also has the same problem of keeping the jsp's in memory. or it was only present in 4.0.4 It's not a *problem* -- it's a *feature* :-). This is one of the keys to maintaining good performance on repeatedly requested pages. Yes, Tomcat 4.1.x maintains a reference to every JSP page that has ever been requested (same as every servlet that has ever been requested) until that webapp is reloaded or removed, or you shut down Tomcat. Given this, designing webapps where you auto-generate hundreds of different JSP pages (which was the choice of the originator of this message thread) is not what you really want to do. Instead, you'd want to use a single JSP page for each basic *style* of output (essentially the JSP page would be a formatting template) that pulls in the unique information for a particular report (from the database, from XML, or whatever) dynamically. Then, a given webpp would likely have 5-10 JSP pages, instead of hundreds. Just as an example, assume that your application back-end gave you the data you need in some XML format, and you want to offer your user the chance to format this data in ten different ways. If you create an XSLT stylesheet to transform the data for each of the ten formats, you can do this all with a *single* JSP page that takes an XML data source and an XSLT stylesheet, applies the transformation, and renders the result. (JSTL has a tag that will do all the grunt work for you.) If you really really want to auto-generate all the reports ahead of time, go ahead and generate static HTML pages -- don't waste your time generating JSP that then has to get compiled, loaded, and executed. As a side benefit, the output will get served a little faster because there is less overhead in serving static files. If you really really really want to generate hundreds of JSP pages, then plan on buying enough memory to hold them all and be done with it. Fortunately, this is not usually a break the bank decision (I just upgraded my development PC to a gigabyte of memory for less than $100 :-). If you really really really really want to generate hundreds of JSP pages, and don't (or can't) afford the memory to hold them all, you only have yourself to blame for the results. saurabh Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: Memory Usage and Garbage Collection
From: Brandon Cruz [EMAIL PROTECTED] Sent: Friday, January 03, 2003 2:23 PM Subject: RE: Memory Usage and Garbage Collection 1)For every single request to a servlet or JSP page, a new instance of that class is created? For example, if there is one JSP page and ten people access that one page over the course of a day, 10 separate instances of the same class are created and will never be gc'd until the webapp or tomcat is restarted? No no no. Ever so confusing. Here's the rub. First, consider that JSP == Servlet. Second, Servlet == Java Class. When a request comes in for a Servlet, the Servlet class is loaded. Then (assuming we're not using a Single Threaded Model Servlet), a new instance of that Servlet is created to handle the request. These instances of the Servlet will inevitably be GC'd in time. However, what will NOT be GC'd is the CLASS of the Servlet. Once the class is loaded, the class stays around until restart. This is because the ClassLoader for the Servlet hangs on to it. For most applications this is not a problem, as Servlets are roughly equivalent to CGI programs. However, where Servlets are similar to CGI programs, some are equating JSPs with HTML files (or, perhaps better, SHTML files). Most normal sites would have very few CGI programs, but may have loads of HTML or SHTML files. But, since JSPs are actually Servlets in cheap clothing, the JSP == HTML file is not a valid assumption to make. Whereas Servlets are usually mostly just logic, JSPs tend to be mostly content. So, when the server loads the Servlet class generated by the JSP, it loads and caches more content than logic. If Apache remembered and cached every HTML file that went through it, you'd end up potentially caching your entire web tree in RAM. If you happen to have enough RAM to support this, it's not a problem. But if your content is growing every day, and old data doesn't go away, you will eventially run out of RAM and Bad Things will happen. Our site has ~1200 JSPs but all told they only add up to about 6MB, and they're static. So, if all of those managed to get sucked into RAM, the space they would take wouldn't even make a 256MB Tomcat instance blink, so it's not a problem for us. But another fella was generating dynamic JSPs, and would thereby eventually starve out his heap because Tomcat wasn't expiring Servlets. The real question is whether JSPs should be considered Different Enough from normal Servlets to warrant adding code to scavenge them. Regards, Will Hartung ([EMAIL PROTECTED]) -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
On Fri, 3 Jan 2003, Brandon Cruz wrote: Date: Fri, 3 Jan 2003 16:23:24 -0600 From: Brandon Cruz [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED], [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Subject: RE: Memory Usage and Garbage Collection Craig, From what you have been saying... 1)For every single request to a servlet or JSP page, a new instance of that class is created? NO! It's exactly the opposite -- the same instance gets reused every time. For example, if there is one JSP page and ten people access that one page over the course of a day, 10 separate instances of the same class are created and will never be gc'd until the webapp or tomcat is restarted? 2)If this is true, it looks to me like any java application in the world eventually has to be restarted as more and more people access it. Buying more memory would prolong the time to restart the application, but eventually all the instances created will take up all the available RAM. Is this correct? The point I was trying to make is that code you *call* from your servlets and JSPs can create memory leaks, and there's not necessarily anything that you (as the author of the servlet or JSP) page can do about it. You can't even tell that it's happening unless you have access to the source code of the classes you're calling. Assume that you implement something like the complex example from my previous mail, and every call to the getOtherObject() method specifies a different id value. The old OtherObject instances will *not* be GC'd, because there are live references to them -- even if they are not in your servlet, they still exist in the JVM. And the fact that there is only one instance of your servlet is not relevant to this memory leak, because it is not your servlet instances that are being accumulated. It is not good enough to just release references in your servlet when you are through with an object. Brandon Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: Memory Usage and Garbage Collection
The same servlet gets called everytime? Isn't this container implementation specific (Although functionally it SHOULD appear to be the same servlet)? For example, couldn't a container do pooling or load balancing. Craig R. McClanahan wrote: On Fri, 3 Jan 2003, Brandon Cruz wrote: Date: Fri, 3 Jan 2003 16:23:24 -0600 From: Brandon Cruz [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED], [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Subject: RE: Memory Usage and Garbage Collection Craig, From what you have been saying... 1)For every single request to a servlet or JSP page, a new instance of that class is created? NO! It's exactly the opposite -- the same instance gets reused every time. For example, if there is one JSP page and ten people access that one page over the course of a day, 10 separate instances of the same class are created and will never be gc'd until the webapp or tomcat is restarted? 2)If this is true, it looks to me like any java application in the world eventually has to be restarted as more and more people access it. Buying more memory would prolong the time to restart the application, but eventually all the instances created will take up all the available RAM. Is this correct? The point I was trying to make is that code you *call* from your servlets and JSPs can create memory leaks, and there's not necessarily anything that you (as the author of the servlet or JSP) page can do about it. You can't even tell that it's happening unless you have access to the source code of the classes you're calling. Assume that you implement something like the complex example from my previous mail, and every call to the getOtherObject() method specifies a different id value. The old OtherObject instances will *not* be GC'd, because there are live references to them -- even if they are not in your servlet, they still exist in the JVM. And the fact that there is only one instance of your servlet is not relevant to this memory leak, because it is not your servlet instances that are being accumulated. It is not good enough to just release references in your servlet when you are through with an object. Brandon Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- = = Management is doing things right; leadership is doing the = = right things.- Peter Drucker= =___= = http://www.sun.com/service/sunps/jdc/javacenter.pdf = = www.sun.com | www.javasoft.com | http://wwws.sun.com/sunone = = -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Instead, you'd want to use a single JSP page for each basic *style* of output (essentially the JSP page would be a formatting template) that pulls in the unique information for a particular report (from the database, from XML, or whatever) dynamically. For example, with the web site for The Mahogany Man (http://www.the-mahogany-man.com), the entire catalog is a single JSP page. There are 100s of items in the catalog. --- Noel -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
There is still a live reference to each OtherObject instance sitting in the static HashMap cache. there is no way to ***ever*** GC this instance Another example of a similar memory leak is the File.deleteOnExit method. It should not be used without extreme care and understanding in a server application, since the system has to hold onto memory related to deleting the file until the JVM shuts down. --- Noel -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: Memory Usage and Garbage Collection
On Thu, 2 Jan 2003, Brandon Cruz wrote: Date: Thu, 2 Jan 2003 16:16:23 -0600 From: Brandon Cruz [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED], [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Subject: Memory Usage and Garbage Collection Do loaded jsp pages and/or class files ever get garbage collected when tomcat is running? It's legal for servlet containers to destroy and release servlets and JSP pages while the server is running, but Tomcat doesn't currently do so. Once a servlet or JSP is loaded, it stays loaded until you reload that particular webapp or you shut Tomcat down. We have a production server with several hundred virtual hosts per host, each with a fair share of jsp pages and with moderate to low traffic per host. As time goes on, the amount of memory being used constantly grows. It starts off around 60MB, then goes higher and higher, getting up to around 100MB after a couple days. The regular GC seems to usually clean up around 2MB ([GC 99493K-97502K(204544K), 0.0243521 secs]) and the Full GC seems to clean up less than that ([Full GC 97388K-97187K(204544K), 2.4269915 secs]). Since I have the -Xmx and -Xms set to 200MB, the 204544K number never gets resized, but the number before the - seems to slowly and steadily rise. Full GC seems to run quite often, every few seconds, GC runs once in a while, but spits out about 50 lines at once every time it runs. Is this normal? Shouldn't Full GC only run once in a while? I am starting to think that as classes and jsp's are loaded, they stay in memory and are never released until tomcat is restarted, which means that there is eventually a point where all the classes will load and I just need to have enough memory to support that without having to use swap space. It's not just the classes -- it's the object instances created from those classes that take up space (the bytecodes of the class itself exist only once). The problem occurs when the memory usage number before the - gets up to about 130. The system is using swap space and eventually out of memory errors start showing up. Any ideas? More Ram, more tuning, different site architecture? If you're using swap space, you probably have your max heap size (-Xmx) too large for the amount of physical memory that is available. I'd definitely start by either reducing -Xmx or increasing the amount of physical RAM. If reducing -Xmx gives you OutOfMemoryException errors, then increasing RAM is the only option. The second thing I'd do is review my applications for places where they might be maintaining references to data in between requests, either in instance variables of the servlet or JSP class or by keeping too many things in the user's session for too long. If there are such references, your user data objects cannot be GC'd and you'll end up with exactly the pattern you describe (slowly increasing memory use). Thanks in advance? Brandon Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
Craig, Thanks for your comments, I still have a few clarification questions. 1)It's not just the classes -- it's the object instances created from those classes that take up space (the bytecodes of the class itself exist only once). ---does this mean that every object instance is never garbage collected, or are these instances collected? 2)What about instances of the classes, does every instance stay in memory forever? Are they loaded into the sessions, or are they pooled somehow? What about the instance variables of these classes, I assume they get collected after the class instances would be collected. If class instances stay in memory forever, I would think there is no possible way to ever keep the system running without a restart. Brandon -Original Message- From: Craig R. McClanahan [mailto:[EMAIL PROTECTED]] Sent: Thursday, January 02, 2003 6:12 PM To: Tomcat Users List; [EMAIL PROTECTED] Subject: Re: Memory Usage and Garbage Collection On Thu, 2 Jan 2003, Brandon Cruz wrote: Date: Thu, 2 Jan 2003 16:16:23 -0600 From: Brandon Cruz [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED], [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Subject: Memory Usage and Garbage Collection Do loaded jsp pages and/or class files ever get garbage collected when tomcat is running? It's legal for servlet containers to destroy and release servlets and JSP pages while the server is running, but Tomcat doesn't currently do so. Once a servlet or JSP is loaded, it stays loaded until you reload that particular webapp or you shut Tomcat down. We have a production server with several hundred virtual hosts per host, each with a fair share of jsp pages and with moderate to low traffic per host. As time goes on, the amount of memory being used constantly grows. It starts off around 60MB, then goes higher and higher, getting up to around 100MB after a couple days. The regular GC seems to usually clean up around 2MB ([GC 99493K-97502K(204544K), 0.0243521 secs]) and the Full GC seems to clean up less than that ([Full GC 97388K-97187K(204544K), 2.4269915 secs]). Since I have the -Xmx and -Xms set to 200MB, the 204544K number never gets resized, but the number before the - seems to slowly and steadily rise. Full GC seems to run quite often, every few seconds, GC runs once in a while, but spits out about 50 lines at once every time it runs. Is this normal? Shouldn't Full GC only run once in a while? I am starting to think that as classes and jsp's are loaded, they stay in memory and are never released until tomcat is restarted, which means that there is eventually a point where all the classes will load and I just need to have enough memory to support that without having to use swap space. It's not just the classes -- it's the object instances created from those classes that take up space (the bytecodes of the class itself exist only once). The problem occurs when the memory usage number before the - gets up to about 130. The system is using swap space and eventually out of memory errors start showing up. Any ideas? More Ram, more tuning, different site architecture? If you're using swap space, you probably have your max heap size (-Xmx) too large for the amount of physical memory that is available. I'd definitely start by either reducing -Xmx or increasing the amount of physical RAM. If reducing -Xmx gives you OutOfMemoryException errors, then increasing RAM is the only option. The second thing I'd do is review my applications for places where they might be maintaining references to data in between requests, either in instance variables of the servlet or JSP class or by keeping too many things in the user's session for too long. If there are such references, your user data objects cannot be GC'd and you'll end up with exactly the pattern you describe (slowly increasing memory use). Thanks in advance? Brandon Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: Memory Usage and Garbage Collection
Looking at the jasper source of tomcat 4.0.4 releasing jsp's seems to be reasonable easy to implement: The Jsp's classloader, the class and the actual jsp-servlet instance are all put together in a JspServletWrapper-Object which itself is stored in the JspServlet (the Servlet used to executing jsps) using a Hashtable. One could replace the hashtable with a LRU-Cache or anything. Since each jsp is loaded using a separate classloader, removing the Wrapper removes the reference to the instance, it's class and it's loader, which should enable the class garbage collector to remove the class. Do you think this approach is reasonable? Does this part of the implementation differ with Jasper2? This is a feature I could really use well. llap, julian - Original Message - From: Craig R. McClanahan [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED]; [EMAIL PROTECTED] Sent: Friday, January 03, 2003 1:12 AM Subject: Re: Memory Usage and Garbage Collection On Thu, 2 Jan 2003, Brandon Cruz wrote: Date: Thu, 2 Jan 2003 16:16:23 -0600 From: Brandon Cruz [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED], [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Subject: Memory Usage and Garbage Collection Do loaded jsp pages and/or class files ever get garbage collected when tomcat is running? It's legal for servlet containers to destroy and release servlets and JSP pages while the server is running, but Tomcat doesn't currently do so. Once a servlet or JSP is loaded, it stays loaded until you reload that particular webapp or you shut Tomcat down. We have a production server with several hundred virtual hosts per host, each with a fair share of jsp pages and with moderate to low traffic per host. As time goes on, the amount of memory being used constantly grows. It starts off around 60MB, then goes higher and higher, getting up to around 100MB after a couple days. The regular GC seems to usually clean up around 2MB ([GC 99493K-97502K(204544K), 0.0243521 secs]) and the Full GC seems to clean up less than that ([Full GC 97388K-97187K(204544K), 2.4269915 secs]). Since I have the -Xmx and -Xms set to 200MB, the 204544K number never gets resized, but the number before the - seems to slowly and steadily rise. Full GC seems to run quite often, every few seconds, GC runs once in a while, but spits out about 50 lines at once every time it runs. Is this normal? Shouldn't Full GC only run once in a while? I am starting to think that as classes and jsp's are loaded, they stay in memory and are never released until tomcat is restarted, which means that there is eventually a point where all the classes will load and I just need to have enough memory to support that without having to use swap space. It's not just the classes -- it's the object instances created from those classes that take up space (the bytecodes of the class itself exist only once). The problem occurs when the memory usage number before the - gets up to about 130. The system is using swap space and eventually out of memory errors start showing up. Any ideas? More Ram, more tuning, different site architecture? If you're using swap space, you probably have your max heap size (-Xmx) too large for the amount of physical memory that is available. I'd definitely start by either reducing -Xmx or increasing the amount of physical RAM. If reducing -Xmx gives you OutOfMemoryException errors, then increasing RAM is the only option. The second thing I'd do is review my applications for places where they might be maintaining references to data in between requests, either in instance variables of the servlet or JSP class or by keeping too many things in the user's session for too long. If there are such references, your user data objects cannot be GC'd and you'll end up with exactly the pattern you describe (slowly increasing memory use). Thanks in advance? Brandon Craig -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
RE: Memory Usage and Garbage Collection
On Thu, 2 Jan 2003, Brandon Cruz wrote: Date: Thu, 2 Jan 2003 19:04:55 -0600 From: Brandon Cruz [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: RE: Memory Usage and Garbage Collection Craig, Thanks for your comments, I still have a few clarification questions. 1)It's not just the classes -- it's the object instances created from those classes that take up space (the bytecodes of the class itself exist only once). ---does this mean that every object instance is never garbage collected, or are these instances collected? Instances can be garbage collected IF AND ONLY IF there are no live references to that object in a static/instance/local variable of some other object that is also in memory. Only instances that are no longer referenced from other object instances can be recycled. In the case at hand, Tomcat (obviously) has references to all the servlets that it has loaded. Therefore, those servlet instances cannot be garbage collected. Furthermore, any object that is referenced by static or instance variables of your servlet class can *also* not be garbage collected, because live references still exist. Same thing for session attributes. In the very early days of Java, classes themselves could be GC'd if there were no live instances of that class. However, this caused more grief than it was worth, so that went away (about JDK 1.1 or so). In today's world, the only way to throw away a class instance is to throw away the class loader that loaded it (which is how Tomcat implements webapp reloading). 2)What about instances of the classes, does every instance stay in memory forever? Are they loaded into the sessions, or are they pooled somehow? What about the instance variables of these classes, I assume they get collected after the class instances would be collected. As above, instances ALWAYS stay in memory as long as there are live references. If there are no live references, the GC is free to clean them up if and when it feels like it. If class instances stay in memory forever, I would think there is no possible way to ever keep the system running without a restart. As above, you can throw away references to a ClassLoader, and that will ultimately cause all the instances to be collected -- but ONLY if there are not any references to any instances of classes loaded by that ClassLoader somewhere else. Phew, that doesn't make sense -- can we describe a sample use case? Sure. Consider the fact that Tomcat provides more than one class loader (see http://jakarta.apache.org/tomcat/tomcat-4.1-doc/class-loader-howto.html). The common and shared class loaders are never thrown away, so any classes loaded from there will stay in memory for the lifetime of Tomcat. But wait, there's more. Assume that you've got a class, loaded from a library in common/lib, that maintains a collection as a static variable. Now, assume you've called a method on this class, and passed it a reference to a bean (or something) that is loaded from your webapp (i.e. it's in WEB-INF/classes or WEB-INF/lib), and this reference gets added to the static collection. Now, ask Tomcat to reload this application. What happens? Tomcat dutifully throws away its reference to the webapp class loader. Normally, that means everything loaded from that class loader is now garbage and can be collected. HOWEVER, because there is still a live reference to one of the objects from your old webapp in the static collection. Therefore, GC cannot process: * The instance of your bean class that was referenced * The class of your bean * The webapp class loader * Any other objects referenced by the webapp class loader. In short, the above scenario just created a memory leak. The best thing you can do to avoid problems like this is to make your webapps self contained, and to always release references to objects you don't need any longer. Brandon Craig -Original Message- From: Craig R. McClanahan [mailto:[EMAIL PROTECTED]] Sent: Thursday, January 02, 2003 6:12 PM To: Tomcat Users List; [EMAIL PROTECTED] Subject: Re: Memory Usage and Garbage Collection On Thu, 2 Jan 2003, Brandon Cruz wrote: Date: Thu, 2 Jan 2003 16:16:23 -0600 From: Brandon Cruz [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED], [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Subject: Memory Usage and Garbage Collection Do loaded jsp pages and/or class files ever get garbage collected when tomcat is running? It's legal for servlet containers to destroy and release servlets and JSP pages while the server is running, but Tomcat doesn't currently do so. Once a servlet or JSP is loaded, it stays loaded until you reload that particular webapp or you shut Tomcat down. We have a production server with several hundred virtual hosts per host, each with a fair share of jsp pages and with moderate to low traffic per host. As time goes
Re: Memory Usage and Garbage Collection
On Fri, 3 Jan 2003, Julian Löffelhardt wrote: Date: Fri, 3 Jan 2003 02:01:58 +0100 From: Julian Löffelhardt [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Subject: Re: Memory Usage and Garbage Collection Looking at the jasper source of tomcat 4.0.4 releasing jsp's seems to be reasonable easy to implement: The Jsp's classloader, the class and the actual jsp-servlet instance are all put together in a JspServletWrapper-Object which itself is stored in the JspServlet (the Servlet used to executing jsps) using a Hashtable. One could replace the hashtable with a LRU-Cache or anything. Since each jsp is loaded using a separate classloader, removing the Wrapper removes the reference to the instance, it's class and it's loader, which should enable the class garbage collector to remove the class. Do you think this approach is reasonable? Does this part of the implementation differ with Jasper2? You'd best examine the sources to figure that out :-). But Jasper2 is radically different than Jasper1. But remember, it's not just a matter of throwing away the reference to the compiled servlet class. You also need to ensure that the destroy() method gets called as the servlet API requires -- all the while ensuring that no additional requests start getting processed through the service method. And, don't forget that this will harm performance for the vast majority of users who *do* have adequate memory on their servers, so nothing like this should be enabled by default. This is a feature I could really use well. llap, julian Craig - Original Message - From: Craig R. McClanahan [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED]; [EMAIL PROTECTED] Sent: Friday, January 03, 2003 1:12 AM Subject: Re: Memory Usage and Garbage Collection On Thu, 2 Jan 2003, Brandon Cruz wrote: Date: Thu, 2 Jan 2003 16:16:23 -0600 From: Brandon Cruz [EMAIL PROTECTED] Reply-To: Tomcat Users List [EMAIL PROTECTED], [EMAIL PROTECTED] To: Tomcat Users List [EMAIL PROTECTED] Subject: Memory Usage and Garbage Collection Do loaded jsp pages and/or class files ever get garbage collected when tomcat is running? It's legal for servlet containers to destroy and release servlets and JSP pages while the server is running, but Tomcat doesn't currently do so. Once a servlet or JSP is loaded, it stays loaded until you reload that particular webapp or you shut Tomcat down. We have a production server with several hundred virtual hosts per host, each with a fair share of jsp pages and with moderate to low traffic per host. As time goes on, the amount of memory being used constantly grows. It starts off around 60MB, then goes higher and higher, getting up to around 100MB after a couple days. The regular GC seems to usually clean up around 2MB ([GC 99493K-97502K(204544K), 0.0243521 secs]) and the Full GC seems to clean up less than that ([Full GC 97388K-97187K(204544K), 2.4269915 secs]). Since I have the -Xmx and -Xms set to 200MB, the 204544K number never gets resized, but the number before the - seems to slowly and steadily rise. Full GC seems to run quite often, every few seconds, GC runs once in a while, but spits out about 50 lines at once every time it runs. Is this normal? Shouldn't Full GC only run once in a while? I am starting to think that as classes and jsp's are loaded, they stay in memory and are never released until tomcat is restarted, which means that there is eventually a point where all the classes will load and I just need to have enough memory to support that without having to use swap space. It's not just the classes -- it's the object instances created from those classes that take up space (the bytecodes of the class itself exist only once). The problem occurs when the memory usage number before the - gets up to about 130. The system is using swap space and eventually out of memory errors start showing up. Any ideas? More Ram, more tuning, different site architecture? If you're using swap space, you probably have your max heap size (-Xmx) too large for the amount of physical memory that is available. I'd definitely start by either reducing -Xmx or increasing the amount of physical RAM. If reducing -Xmx gives you OutOfMemoryException errors, then increasing RAM is the only option. The second thing I'd do is review my applications for places where they might be maintaining references to data in between requests, either in instance variables of the servlet or JSP class or by keeping too many things in the user's session for too long. If there are such references, your user data objects cannot be GC'd and you'll end up with exactly the pattern you describe (slowly increasing memory use). Thanks in advance? Brandon Craig