1 22 package org.jboss.test.aop.memoryleaks; 23 24 import java.io.File ; 25 import java.io.FileOutputStream ; 26 import java.io.PrintStream ; 27 import java.lang.ref.WeakReference ; 28 import java.lang.reflect.Field ; 29 import java.lang.reflect.Method ; 30 import java.net.URL ; 31 import java.net.URLClassLoader ; 32 import java.util.ArrayList ; 33 import java.util.Enumeration ; 34 import java.util.Properties ; 35 import java.util.StringTokenizer ; 36 37 import junit.framework.TestCase; 38 39 import org.jboss.profiler.jvmti.JVMTIInterface; 40 41 45 public class MemoryLeakTester extends TestCase 46 { 47 48 52 public MemoryLeakTester(String name) 53 { 54 super(name); 55 } 56 57 public MemoryLeakTester() 58 { 59 super(); 60 } 61 62 private static void printVariables() 63 { 64 Properties props = System.getProperties(); 65 Enumeration iter = props.keys(); 66 67 System.out.println("properties:"); 68 while (iter.hasMoreElements()) 69 { 70 Object key = iter.nextElement(); 71 System.out.println(key + "=" + props.get(key)); 72 System.out.println(); 73 } 74 } 75 76 private static ClassLoader newClassLoader() throws Exception { 77 URL classLocation = MemoryLeakTester.class.getProtectionDomain().getCodeSource().getLocation(); 79 StringTokenizer tokenString = new StringTokenizer (System.getProperty("java.class.path"),File.pathSeparator); 80 String 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 urls = new ArrayList (); 91 while (tokenString.hasMoreElements()) 92 { 93 String value = tokenString.nextToken(); 94 URL itemLocation = new File (value).toURL(); 95 if (!itemLocation.equals(classLocation) && !itemLocation.toString().equals(pathIgnore)) 96 { 97 urls.add(itemLocation); 99 } 100 } 101 102 URL [] urlArray= (URL [])urls.toArray(new URL [urls.size()]); 103 104 ClassLoader masterClassLoader = URLClassLoader.newInstance(urlArray,null); 105 106 107 ClassLoader appClassLoader = URLClassLoader.newInstance(new URL [] {classLocation},masterClassLoader); 108 109 return appClassLoader; 110 } 111 112 113 private void undeploy(Class xmlLoader) throws Exception 114 { 115 String strurl = (String )System.getProperty("jboss.aop.path"); 116 assertNotNull("Property jboss.aop.path should be defined",strurl); 117 strurl = strurl.replace('\\','/'); 118 URL url = new URL ("file:/" + strurl); 119 120 Method method = xmlLoader.getDeclaredMethod("undeployXML", new Class [] {URL .class}); 121 method.invoke(null, new Object [] {url}); 122 } 124 125 public void testWithClassLoader() throws Exception 126 { 127 WeakReference weakReferenceOnLoader = null; 128 Class xmlLoader = null; try 132 { 133 { 134 ClassLoader oldloader = Thread.currentThread().getContextClassLoader(); 135 ClassLoader loader = newClassLoader(); 136 weakReferenceOnLoader = new WeakReference (loader); 137 138 Thread.currentThread().setContextClassLoader(loader); 139 140 Class 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 aspectManagerClass = loader.loadClass("org.jboss.aop.AspectManager"); 145 assertNotSame(aspectManagerClass.getClassLoader(), this.getClass().getClassLoader()); 146 147 Class pojoClass = loader.loadClass("org.jboss.test.aop.memoryleaks.POJO"); 148 assertNotSame(pojoClass.getClassLoader(), this.getClass().getClassLoader()); 149 150 Class interceptorClass = loader.loadClass("org.jboss.test.aop.memoryleaks.TestInterceptor"); 151 assertNotSame(interceptorClass.getClassLoader(), this.getClass().getClassLoader()); 152 153 Class 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 aopinterceptorClass = loader.loadClass("org.jboss.aop.advice.Interceptor"); 161 assertSame(aopinterceptorClass.getClassLoader(),xmlLoader.getClassLoader()); 162 165 Object pojo = null; 166 pojo = pojoClass.newInstance(); 167 168 Method testMethod =null; 169 testMethod = pojoClass.getMethod("method", new Class [] {}); 170 testMethod.invoke(pojo, new Object [] {}); 171 172 Field icptrIntercepted = interceptorClass.getDeclaredField("intercepted"); 173 Field 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 [] {}); 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 Thread.currentThread().setContextClassLoader(oldloader); 201 } 202 203 assertEquals(1, countInstances("org.jboss.aop.AspectManager")); 204 checkUnload( weakReferenceOnLoader,"org.jboss.test.aop.memoryleaks.TestAspect"); 206 } 207 catch (Exception e) 208 { 209 e.printStackTrace(); 210 throw e; 211 } 212 213 assertNotNull("The masterClassLoader needs to keep a reference, only the customer's classLoader needs to go away",xmlLoader); 215 216 217 219 } 220 221 private void checkUnload(WeakReference weakReferenceOnLoader, String className) throws Exception 222 { 223 JVMTIInterface jvmti = new JVMTIInterface(); 224 if (jvmti.isActive()) 225 { 226 227 229 jvmti.forceReleaseOnSoftReferences(); 230 jvmti.forceGC(); 231 Class clazz = jvmti.getClassByName(className); 232 if (clazz!=null) 233 { 234 jvmti.heapSnapshot("snapshot", "mem"); 235 clazz=null; 236 237 String report =jvmti.exploreClassReferences(className, 10, true, false, false, false, false); 238 239 File outputfile = new File ("./leaks-report.html"); 241 FileOutputStream outfile = new FileOutputStream (outputfile); 242 PrintStream realoutput = new PrintStream (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 [] getDeclaredFields(Class clazz) 263 { 264 ArrayList list = new ArrayList (); 265 for (Class classIteration = clazz;classIteration!=null;classIteration=classIteration.getSuperclass()) 266 { 267 Field [] 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 []) list.toArray(new Field [list.size()]); 277 } 278 279 280 private void clearEverySingleFieldOnInstances(String className) 281 { 282 System.out.println("Clearing " + className); 283 JVMTIInterface jvmti = new JVMTIInterface(); 284 Class classes[] = jvmti.getLoadedClasses(); 285 Object objects[] = null; 286 287 for (int i=0;i<classes.length;i++) 288 { 289 if (classes[i].getName().equals(className)) 290 { 291 Field 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 object, Field [] fields) 308 { 309 for (int fieldN=0;fieldN<fields.length;fieldN++) 310 { 311 try 312 { 313 fields[fieldN].set(object,null); 315 } 317 catch (Exception e) 318 { 319 } 322 } 323 } 324 325 private int countInstances(String name) 326 { 327 JVMTIInterface jvmti = new JVMTIInterface(); 328 int i = jvmti.getAllObjects(name).length; 329 return i; 330 } 331 332 private void unregisterClassLoader(Class aspectManagerClass, ClassLoader loader) throws Exception 333 { 334 Method instance = aspectManagerClass.getDeclaredMethod("instance", new Class [0]); 335 Object aspectManager = instance.invoke(null, new Object [0]); 336 337 Method unregisterClassLoader = aspectManagerClass.getDeclaredMethod("unregisterClassLoader", new Class [] {ClassLoader .class}); 338 unregisterClassLoader.invoke(aspectManager, new Object [] {loader}); 339 } 340 } 341 | Popular Tags |