Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
krumts
Advisor
Advisor
0 Kudos
h3. Introduction Sometimes when a JEE application is stopped, restarted or redeployed on the SAP NetWeaver platform the ClassLoader associated with this application is not properly removed from the heap. This can lead on one side to resource problems (i.e. it's small a memory leak), on the other side to some functional errors, for example unexpected ClassCastExceptions. In this blog I am going to look at some of the common reasons for such kind of problems. I will also show how such problems can be easily analyzed using heap dumps and with the help of the Memory Analyzer tool with some additional NetWeaver specific extensions. h3. Getting the Tools in Place  Let's look first what possibilities there are to analyze such kind of problems. Then I will explain some of the most common reasons with concrete examples.  First, you will need some data for analysis. And as I mentioned already this data is a heap dump. You can find a description how to get a heap dump here  (https://wiki.sdn.sap.com/wiki/pages/viewpage.action?pageId=33456). Of course the heap dump should be taken at a time you suppose or see the problems appear.    Next, let's setup the tools - you need to get the Memory Analyzer tool (now, as it is already open source, you can get it from the Eclipse site  (http://www.eclipse.org/mat/)). You also need to equip the Memory Analyzer with our specific NetWeaver extensions. See description {code:html}here{code}.  h3. Finding the Leaking Loaders   Now that we have all tools in place, let's go to the analysis. So, how do I find that there is a left-over ClassLoader in the heap? Well, just open the heap dump with the Memory Analyzer, and then run the "Leaking Loaders" query from the "SAP NetWeaver Application Server" group.   If there are any such loaders, this query should list them. Below is an example, where two ClassLoaders were not properly released - one for application "demo.memory.loaders.SampleApp1" and one for "demo.memory.loaders.SampleApp1".How does this work? We know exactly where in the heap we can find the list of registered ClassLoaders for active applications, i.e. which class represents the ClassLoader registry, where it stores its data, etc... We also know the class names of the ClassLoaders used to load applications, services, libraries. The query just takes all instances of these known classes, and finds which of them are not in the registry. It is so easy. And, as part of the coding in the NetWeaver extensions is responsible to extract the proper name of the ClassLoaders, we also show the application names. Once we have the list of all leaking loaders, we can analyze why they are in the heap. While I do this I will show some concrete examples. h3. Why Are ClassLoaders Not Released?  As we know already which are the problematic ClassLoaders we only have to find who is keeping them in memory. There are several ways to analyze this, but I personally find the most convenient and easy one is to look at the shortest paths from the GC Root objects to the leaking objects. Just pick one ClassLoader from the list and choose from the context menu "Shortest Path To GC Roots".  Let's look now at some possible paths. h4. The Trivial Case - There Is a "Normal" Reference to the ClassLoader  As any other object, the ClassLoader will be kept in the heap as long as there are references to it. Which are the references can be very easily seen looking at the paths. In this concrete example, the "demo.memory.loaders.SampleApp" ClassLoader is referenced from the "*key*" field of a LinkedHashMap$Entry. Looking down the path we can see that this LinkedHashMap is the "*parents*" field of our sample ClassFinder class. Having in the path all involved classes and field names should make it very easy for a person familiar with the coding to figure out the problem.  h4. A Common Case - Context ClassLoader of a Thread  Another case which I often see is that a leaking ClassLoader is set as the context ClassLoader of a thread, i.e. referenced from the contextClassLoader field of the Thread instance. Here is how the path from the GC roots looks like:Sometimes applications start threads on their own. I wouldn't like to comment if this is a good practice for a JEE application. Fact is that it happens. When the application starts its own thread (on the image above "My Own Thread"), the ClassLoader of the application is set as the contextClassLoader for this thread. If the application then does not take care to somehow make this thread finish when it (the app) is stopped, then the ClassLoader remains in memory. This problem actually belongs to the previously described group of problems - i.e. the loader is strongly referenced. The difference is that the referencing is done implicitly, and not actively by the application developers and is therefore often overlooked. h4. The Registry Problem - One Instance Is Enough  Here is another example of a common reason for leaking ClassLoaders. Imagine that application "demo.memory.A" (or only A for short) has declared dependency on some other application (or library) B and is therefore able to use classes from B. This is so far fine. But imagine that the B is some kind of a registry (for listeners, tracing, whatever...). The application A actively uses classes from B and registers its own (A) instances there (in B). If then A is redeployed, and there is no special care taken from A to unregister the "old" instances from the registry while stopping, then they will stay there. B will not be restarted, as the dependency is from A to B, not from B to A. As long as the outdated instances of A are alive, they will keep their class alive. And the class will keep the ClassLoader alive. Here is a path which shows such an issue:
8 Comments