KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > test > aop > memoryleaks > MemoryLeakTester


1    /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.test.aop.memoryleaks;
23
24 import java.io.File JavaDoc;
25 import java.io.FileOutputStream JavaDoc;
26 import java.io.PrintStream JavaDoc;
27 import java.lang.ref.WeakReference JavaDoc;
28 import java.lang.reflect.Field JavaDoc;
29 import java.lang.reflect.Method JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.net.URLClassLoader JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.Properties JavaDoc;
35 import java.util.StringTokenizer JavaDoc;
36
37 import junit.framework.TestCase;
38
39 import org.jboss.profiler.jvmti.JVMTIInterface;
40
41 /**
42  *
43  * @author <a HREF="clebert.suconic@jboss.com">Clebert Suconic</a>
44  */

45 public class MemoryLeakTester extends TestCase
46 {
47    
48    /**
49     * Constructor for UndeployTester.
50     * @param arg0
51     */

52    public MemoryLeakTester(String JavaDoc name)
53    {
54       super(name);
55    }
56    
57    public MemoryLeakTester()
58    {
59       super();
60    }
61
62    private static void printVariables()
63    {
64       Properties JavaDoc props = System.getProperties();
65       Enumeration JavaDoc iter = props.keys();
66       
67       System.out.println("properties:");
68       while (iter.hasMoreElements())
69       {
70          Object JavaDoc key = iter.nextElement();
71          System.out.println(key + "=" + props.get(key));
72          System.out.println();
73       }
74    }
75
76    private static ClassLoader JavaDoc newClassLoader() throws Exception JavaDoc {
77        //printVariables();
78
URL JavaDoc classLocation = MemoryLeakTester.class.getProtectionDomain().getCodeSource().getLocation();
79        StringTokenizer JavaDoc tokenString = new StringTokenizer JavaDoc(System.getProperty("java.class.path"),File.pathSeparator);
80        String JavaDoc pathIgnore = System.getProperty("path.ignore");
81        if (pathIgnore==null)
82        {
83           pathIgnore = classLocation.toString();
84        } else
85        {
86           System.out.println("pathIgnore=" + pathIgnore);
87        }
88        
89        
90        ArrayList JavaDoc urls = new ArrayList JavaDoc();
91        while (tokenString.hasMoreElements())
92        {
93           String JavaDoc value = tokenString.nextToken();
94           URL JavaDoc itemLocation = new File JavaDoc(value).toURL();
95           if (!itemLocation.equals(classLocation) && !itemLocation.toString().equals(pathIgnore))
96           {
97              //System.out.println("Location:" + itemLocation);
98
urls.add(itemLocation);
99           }
100        }
101        
102        URL JavaDoc[] urlArray= (URL JavaDoc[])urls.toArray(new URL JavaDoc[urls.size()]);
103        
104        ClassLoader JavaDoc masterClassLoader = URLClassLoader.newInstance(urlArray,null);
105        
106        
107        ClassLoader JavaDoc appClassLoader = URLClassLoader.newInstance(new URL JavaDoc[] {classLocation},masterClassLoader);
108        
109        return appClassLoader;
110     }
111        
112
113    private void undeploy(Class JavaDoc xmlLoader) throws Exception JavaDoc
114    {
115       String JavaDoc strurl = (String JavaDoc)System.getProperty("jboss.aop.path");
116       assertNotNull("Property jboss.aop.path should be defined",strurl);
117       strurl = strurl.replace('\\','/');
118       URL JavaDoc url = new URL JavaDoc("file:/" + strurl);
119       
120       Method JavaDoc method = xmlLoader.getDeclaredMethod("undeployXML", new Class JavaDoc[] {URL JavaDoc.class});
121       method.invoke(null, new Object JavaDoc[] {url});
122       //AspectXmlLoader.undeployXML(url); -- I need to use reflection operations as I don't want to take the chance on letting the JVM using a different classLoader
123
}
124    
125    public void testWithClassLoader() throws Exception JavaDoc
126    {
127       WeakReference JavaDoc weakReferenceOnLoader = null;
128       Class JavaDoc xmlLoader = null; // we need to keep that reference, so only the customer's classLoader will go away.
129
// If the classLoader was cleared, referenceClassLoader.get() will be null on assertions.
130
// If JBossProfiler/jvmti is available (configured with -agentlib:jbossAgent) we will use it for the assertion, if not we will use this weakReference
131
try
132       {
133       {
134          ClassLoader JavaDoc oldloader = Thread.currentThread().getContextClassLoader();
135          ClassLoader JavaDoc loader = newClassLoader();
136          weakReferenceOnLoader = new WeakReference JavaDoc(loader);
137          
138          Thread.currentThread().setContextClassLoader(loader);
139    
140          Class JavaDoc testClass = loader.loadClass("org.jboss.test.aop.memoryleaks.Test");
141          assertSame("Fix your classpath, this test is not valid",loader, testClass.getClassLoader());
142          assertNotSame(testClass.getClassLoader(), this.getClass().getClassLoader());
143          
144          Class JavaDoc aspectManagerClass = loader.loadClass("org.jboss.aop.AspectManager");
145          assertNotSame(aspectManagerClass.getClassLoader(), this.getClass().getClassLoader());
146
147          Class JavaDoc pojoClass = loader.loadClass("org.jboss.test.aop.memoryleaks.POJO");
148          assertNotSame(pojoClass.getClassLoader(), this.getClass().getClassLoader());
149
150          Class JavaDoc interceptorClass = loader.loadClass("org.jboss.test.aop.memoryleaks.TestInterceptor");
151          assertNotSame(interceptorClass.getClassLoader(), this.getClass().getClassLoader());
152          
153          Class JavaDoc aspectClass = loader.loadClass("org.jboss.test.aop.memoryleaks.TestAspect");
154          assertNotSame(interceptorClass.getClassLoader(), this.getClass().getClassLoader());
155          
156          xmlLoader = loader.loadClass("org.jboss.aop.AspectXmlLoader");
157          assertNotSame(xmlLoader.getClassLoader(),loader);
158          
159          
160          Class JavaDoc aopinterceptorClass = loader.loadClass("org.jboss.aop.advice.Interceptor");
161          assertSame(aopinterceptorClass.getClassLoader(),xmlLoader.getClassLoader());
162          //System.out.println("testWithClassLoader ChildClassLoader = " + xmlLoader.getClassLoader());
163
//ClassLoader superLoader = xmlLoader.getClassLoader();
164

165          Object JavaDoc pojo = null;
166          pojo = pojoClass.newInstance();
167          
168          Method JavaDoc testMethod =null;
169          testMethod = pojoClass.getMethod("method", new Class JavaDoc[] {});
170          testMethod.invoke(pojo, new Object JavaDoc[] {});
171          
172          Field JavaDoc icptrIntercepted = interceptorClass.getDeclaredField("intercepted");
173          Field JavaDoc aspectIntercepted = aspectClass.getDeclaredField("intercepted");
174          
175          assertTrue(icptrIntercepted.getBoolean(null));
176          assertTrue(aspectIntercepted.getBoolean(null));
177          
178          icptrIntercepted.setBoolean(null,false);
179          aspectIntercepted.setBoolean(null,false);
180
181          undeploy(xmlLoader);
182
183          testMethod.invoke(pojo, new Object JavaDoc[] {});
184
185          assertFalse(icptrIntercepted.getBoolean(null));
186          assertFalse(aspectIntercepted.getBoolean(null));
187          
188          unregisterClassLoader(aspectManagerClass, loader);
189          
190          icptrIntercepted=null;
191          aspectIntercepted=null;
192          loader=null;
193          testClass=null;
194          pojoClass=null;
195          pojo = null;
196          interceptorClass = null;
197          aspectClass = null;
198          testMethod = null;
199          //xmlLoader = null;
200
Thread.currentThread().setContextClassLoader(oldloader);
201       }
202
203       assertEquals(1, countInstances("org.jboss.aop.AspectManager"));
204       //checkUnload( weakReferenceOnLoader,"org.jboss.test.aop.memoryleaks.Test");
205
checkUnload( weakReferenceOnLoader,"org.jboss.test.aop.memoryleaks.TestAspect");
206       }
207       catch (Exception JavaDoc e)
208       {
209          e.printStackTrace();
210          throw e;
211       }
212      
213       // I'm pretty sure nobody would clear that reference. I'm keeping this assertion here just to make it clear why we can't clear xmlLoader
214
assertNotNull("The masterClassLoader needs to keep a reference, only the customer's classLoader needs to go away",xmlLoader);
215       
216
217       /*Class pojoClass = loader.loadClass("org.jboss.test.aop.memoryleaks.POJO");
218       Class interceptorClass = loader.loadClass("org.jboss.test.aop.memoryleaks.TestInterceptor"); */

219    }
220
221    private void checkUnload(WeakReference JavaDoc weakReferenceOnLoader, String JavaDoc className) throws Exception JavaDoc
222    {
223       JVMTIInterface jvmti = new JVMTIInterface();
224       if (jvmti.isActive())
225       {
226          
227          //clearEverySingleFieldOnInstances("org.jboss.aop.AspectManager"); // This part is not intended to be commited. It could be used during debug, and you could use to release references on purpose, just to evaluate behavior
228

229          jvmti.forceReleaseOnSoftReferences();
230          jvmti.forceGC();
231          Class JavaDoc clazz = jvmti.getClassByName(className);
232          if (clazz!=null)
233          {
234             jvmti.heapSnapshot("snapshot", "mem");
235             clazz=null;
236             
237             String JavaDoc report =jvmti.exploreClassReferences(className, 10, true, false, false, false, false);
238             
239             //System.out.println(report);
240
File JavaDoc outputfile = new File JavaDoc("./leaks-report.html");
241             FileOutputStream JavaDoc outfile = new FileOutputStream JavaDoc(outputfile);
242             PrintStream JavaDoc realoutput = new PrintStream JavaDoc(outfile);
243             realoutput.println(report);
244             realoutput.close();
245             
246             
247             jvmti.forceGC();
248             
249             clazz = jvmti.getClassByName(className);
250             
251             if (clazz==null)
252             {
253                 System.out.println("Attention: After clearing every field on AspectManager, GC could release the classLoader");
254             }
255             
256             fail ("Class " + className + " still referenced. Look at report for more details");
257          }
258       }
259       assertNull("The classLoader is supposed to be released. Something is holding a reference. If you activate -agentlib:jbossAgent this testcase will generate a report with referenceHolders.",weakReferenceOnLoader.get());
260    }
261    
262    public Field JavaDoc[] getDeclaredFields(Class JavaDoc clazz)
263    {
264       ArrayList JavaDoc list = new ArrayList JavaDoc();
265       for (Class JavaDoc classIteration = clazz;classIteration!=null;classIteration=classIteration.getSuperclass())
266       {
267           Field JavaDoc[] fields = classIteration.getDeclaredFields();
268           for (int i = 0; i < fields.length; i++)
269           {
270              fields[i].setAccessible(true);
271              list.add(fields[i]);
272           }
273           
274       }
275       
276       return (Field JavaDoc[]) list.toArray(new Field JavaDoc[list.size()]);
277    }
278    
279    
280    private void clearEverySingleFieldOnInstances(String JavaDoc className)
281    {
282       System.out.println("Clearing " + className);
283       JVMTIInterface jvmti = new JVMTIInterface();
284       Class JavaDoc classes[] = jvmti.getLoadedClasses();
285       Object JavaDoc objects[] = null;
286       
287       for (int i=0;i<classes.length;i++)
288       {
289          if (classes[i].getName().equals(className))
290          {
291             Field JavaDoc fields[] = getDeclaredFields(classes[i]);
292             objects = jvmti.getAllObjects(classes[i]);
293             for (int j=0;j<objects.length;j++)
294             {
295                resetObject(objects[j], fields);
296             }
297             if (objects.length==0)
298             {
299                resetObject(null, fields);
300             }
301          }
302       }
303       classes= null;
304       objects = null;
305    }
306
307    private static void resetObject(Object JavaDoc object, Field JavaDoc[] fields)
308    {
309       for (int fieldN=0;fieldN<fields.length;fieldN++)
310       {
311          try
312          {
313             //System.out.print("Setting "+fields[fieldN].getName());
314
fields[fieldN].set(object,null);
315             //System.out.println("...done");
316
}
317          catch (Exception JavaDoc e)
318          {
319            // System.out.println("...error " + e.getMessage());
320
//System.out.println("Exception " + e.getMessage() + " happened during setField");
321
}
322       }
323    }
324
325    private int countInstances(String JavaDoc name)
326    {
327       JVMTIInterface jvmti = new JVMTIInterface();
328       int i = jvmti.getAllObjects(name).length;
329       return i;
330    }
331
332    private void unregisterClassLoader(Class JavaDoc aspectManagerClass, ClassLoader JavaDoc loader) throws Exception JavaDoc
333    {
334       Method JavaDoc instance = aspectManagerClass.getDeclaredMethod("instance", new Class JavaDoc[0]);
335       Object JavaDoc aspectManager = instance.invoke(null, new Object JavaDoc[0]);
336       
337       Method JavaDoc unregisterClassLoader = aspectManagerClass.getDeclaredMethod("unregisterClassLoader", new Class JavaDoc[] {ClassLoader JavaDoc.class});
338       unregisterClassLoader.invoke(aspectManager, new Object JavaDoc[] {loader});
339    }
340 }
341
Popular Tags