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.Constructor ; 29 import java.lang.reflect.Field ; 30 import java.lang.reflect.Method ; 31 import java.net.URL ; 32 import java.net.URLClassLoader ; 33 import java.security.AccessController ; 34 import java.security.PrivilegedAction ; 35 import java.util.ArrayList ; 36 import java.util.Enumeration ; 37 import java.util.Iterator ; 38 import java.util.Properties ; 39 import java.util.StringTokenizer ; 40 import java.util.logging.LogManager ; 41 42 import junit.framework.TestCase; 43 44 import org.jboss.profiler.jvmti.JVMTIInterface; 45 46 51 public class MemoryLeakTestCase extends TestCase 52 { 53 54 58 public MemoryLeakTestCase(String name) 59 { 60 super(name); 61 } 62 63 public MemoryLeakTestCase() 64 { 65 super(); 66 } 67 68 public void testWithClassLoader() throws Exception  69 { 70 71 LogManager.getLogManager(); WeakReference weakReferenceOnLoader = null; 73 Class xmlLoader = null; try 77 { 78 String className = null; 79 { 80 ClassLoader oldloader = Thread.currentThread().getContextClassLoader(); 81 ClassLoader loader = newClassLoader(); 82 weakReferenceOnLoader = new WeakReference (loader); 83 84 Thread.currentThread().setContextClassLoader(loader); 85 86 Class testClass = getTestCaseClass(loader); 87 className = testClass.getName(); 88 89 Class aspectManagerClass = loader.loadClass("org.jboss.aop.AspectManager"); 90 assertNotSame(aspectManagerClass.getClassLoader(), this.getClass().getClassLoader()); 91 92 System.out.println("oldLoader"); 93 94 xmlLoader = loader.loadClass("org.jboss.aop.AspectXmlLoader"); 95 assertNotSame(xmlLoader.getClassLoader(),loader); 96 97 ArrayList methods = getTestMethods(testClass); 98 Object testInstance = getTestInstance(testClass); 99 100 boolean passed = runTests(testInstance, methods); 101 assertTrue(passed); 102 103 undeploy(xmlLoader); 104 105 passed = runTests(testInstance, methods, true); 106 System.out.println("============ Ran tests after undeploy with errors: " + passed); 107 108 unregisterClassLoader(aspectManagerClass, loader); 109 110 loader=null; 111 testClass=null; 112 testInstance = null; 113 methods.clear(); 114 Thread.currentThread().setContextClassLoader(oldloader); 116 } 117 118 assertEquals(1, countInstances("org.jboss.aop.AspectManager", true)); 119 checkUnload( weakReferenceOnLoader, className); 121 122 assertNotNull("The masterClassLoader needs to keep a reference, only the customer's classLoader needs to go away",xmlLoader); 124 } 125 catch (Exception e) 126 { 127 e.printStackTrace(); 128 throw e; 129 } 130 131 System.out.println("Done!"); 132 } 133 134 private Object getTestInstance(Class testClass) throws Exception  135 { 136 137 Constructor [] constructors = testClass.getConstructors(); 138 Constructor defaultConstructor = null; 139 Constructor nameConstructor = null; 140 141 for (int i = 0 ; i < constructors.length ; i++) 142 { 143 System.out.println("found ctor " + constructors[i]); 144 Class [] params = constructors[i].getParameterTypes(); 145 146 if (params.length == 0) 147 { 148 defaultConstructor = constructors[i]; 149 } 150 else if (params.length == 1 && params[i].equals(String .class)) 151 { 152 nameConstructor = constructors[i]; 153 } 154 } 155 156 if (nameConstructor != null) 157 { 158 return nameConstructor.newInstance(new Object [] {testClass.getName()}); 159 } 160 if (defaultConstructor != null) 161 { 162 return defaultConstructor.newInstance(new Object [0]); 163 } 164 throw new RuntimeException ("Could not find a constructor for " + testClass.getName()); 165 } 166 private ArrayList getTestMethods(Class testClass) 167 { 168 System.out.println("Determining test methods"); 169 ArrayList testMethods = new ArrayList (); 170 Method methods[] = testClass.getMethods(); 171 for (int i = 0 ; i < methods.length ; i++) 172 { 173 if (methods[i].getName().indexOf("test") == 0 && methods[i].getParameterTypes().length == 0 && methods[i].getReturnType().equals(Void.TYPE)) 174 { 175 testMethods.add(methods[i]); 176 } 177 } 178 return testMethods; 179 } 180 181 private boolean runTests(Object testInstance, ArrayList methods) 182 { 183 return runTests(testInstance, methods, false); 184 } 185 186 private boolean runTests(Object testInstance, ArrayList methods, boolean breakOnError) 187 { 188 Method setup = null; 189 try 190 { 191 setup = testInstance.getClass().getDeclaredMethod("setUp", new Class [0]); 192 setup.setAccessible(true); 193 } 194 catch (Exception e) 195 { 196 } 197 198 Method tearDown = null; 199 try 200 { 201 tearDown = testInstance.getClass().getDeclaredMethod("tearDown", new Class [0]); 202 tearDown.setAccessible(true); 203 } 204 catch (Exception e) 205 { 206 } 207 208 boolean passed = true; 209 for (Iterator it = methods.iterator() ; it.hasNext() ; ) 210 { 211 Method test = (Method )it.next(); 212 try 213 { 214 System.out.println("============ Running test " + testInstance.getClass().getName() + "." + test.getName()); 215 216 if (setup != null) 217 { 218 setup.invoke(testInstance, new Object [0]); 219 } 220 221 test.invoke(testInstance, new Object [0]); 222 if (!breakOnError) 223 { 224 System.out.println("============ Succeeded test " + testInstance.getClass().getName() + "." + test.getName()); 225 } 226 } 227 catch(Throwable t) 228 { 229 passed = false; 230 if (breakOnError) 231 { 232 break; 233 } 234 else 235 { 236 System.out.println("============ Failed test " + testInstance.getClass().getName() + "." + test.getName() + "\n" + t); 237 t.printStackTrace(); 238 } 239 } 240 finally 241 { 242 if (tearDown != null) 243 { 244 try 245 { 246 tearDown.invoke(testInstance, new Object [0]); 247 } 248 catch(Exception e) 249 { 250 } 251 } 252 253 } 254 } 255 256 return passed; 257 } 258 259 private Class getTestCaseClass(ClassLoader loader) throws Exception  260 { 261 String className = System.getProperty("test.to.run"); 262 assertNotNull("Test to be run must be passed in test.to.run system property", className); 263 264 Class testClass = loader.loadClass(className); 265 assertSame("Fix your classpath, this test is not valid",loader, testClass.getClassLoader()); 266 assertNotSame(testClass.getClassLoader(), this.getClass().getClassLoader()); 267 return testClass; 268 } 269 270 private void checkUnload(WeakReference weakReferenceOnLoader, String className) throws Exception  271 { 272 JVMTIInterface jvmti = new JVMTIInterface(); 273 if (jvmti.isActive()) 274 { 275 276 278 jvmti.forceReleaseOnSoftReferences(); 279 jvmti.forceGC(); 280 Class clazz = jvmti.getClassByName(className); 281 if (clazz!=null) 282 { 283 jvmti.heapSnapshot("snapshot", "mem"); 284 clazz=null; 285 286 String report =jvmti.exploreClassReferences(className, 15, true, false, false, false, false); 287 288 String reportDir = System.getProperty("leak.report.dir"); 290 assertNotNull("You must pass in the directory for the reports as leak.report.dir", reportDir); 291 File outputfile = new File (reportDir + "/leak-reoprt-" + className + ".html"); 292 FileOutputStream outfile = new FileOutputStream (outputfile); 293 PrintStream realoutput = new PrintStream (outfile); 294 realoutput.println(report); 295 realoutput.close(); 296 297 298 jvmti.forceGC(); 299 300 clazz = jvmti.getClassByName(className); 301 302 if (clazz==null) 303 { 304 System.out.println("Attention: After clearing every field on AspectManager, GC could release the classLoader"); 305 } 306 307 fail ("Class " + className + " still referenced. Look at report for more details"); 308 } 309 } 310 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()); 311 } 312 313 public Field [] getDeclaredFields(Class clazz) 314 { 315 ArrayList list = new ArrayList (); 316 for (Class classIteration = clazz;classIteration!=null;classIteration=classIteration.getSuperclass()) 317 { 318 Field [] fields = classIteration.getDeclaredFields(); 319 for (int i = 0; i < fields.length; i++) 320 { 321 fields[i].setAccessible(true); 322 list.add(fields[i]); 323 } 324 325 } 326 327 return (Field []) list.toArray(new Field [list.size()]); 328 } 329 330 331 private void clearEverySingleFieldOnInstances(String className) 332 { 333 System.out.println("Clearing " + className); 334 JVMTIInterface jvmti = new JVMTIInterface(); 335 Class classes[] = jvmti.getLoadedClasses(); 336 Object objects[] = null; 337 338 for (int i=0;i<classes.length;i++) 339 { 340 if (classes[i].getName().equals(className)) 341 { 342 Field fields[] = getDeclaredFields(classes[i]); 343 objects = jvmti.getAllObjects(classes[i]); 344 for (int j=0;j<objects.length;j++) 345 { 346 resetObject(objects[j], fields); 347 } 348 if (objects.length==0) 349 { 350 resetObject(null, fields); 351 } 352 } 353 } 354 classes= null; 355 objects = null; 356 } 357 358 private static void resetObject(Object object, Field [] fields) 359 { 360 for (int fieldN=0;fieldN<fields.length;fieldN++) 361 { 362 try 363 { 364 fields[fieldN].set(object,null); 366 } 368 catch (Exception e) 369 { 370 } 373 } 374 } 375 376 private int countInstances(String name, boolean notSubClasses) 377 { 378 JVMTIInterface jvmti = new JVMTIInterface(); 379 Object [] objects = jvmti.getAllObjects(name); 380 int subClasses = 0; 381 for (int i = 0 ; i < objects.length ; i++) 382 { 383 if (!objects[i].getClass().getName().equals(name)) 384 { 385 subClasses++; 386 } 387 } 388 389 return objects.length - subClasses; 390 } 391 392 private void unregisterClassLoader(Class aspectManagerClass, ClassLoader loader) throws Exception  393 { 394 System.out.println("============ Unregistering ClassLoader"); 395 Method instance = aspectManagerClass.getDeclaredMethod("instance", new Class [0]); 396 Object aspectManager = instance.invoke(null, new Object [0]); 397 398 Method unregisterClassLoader = aspectManagerClass.getDeclaredMethod("unregisterClassLoader", new Class [] {ClassLoader .class}); 399 unregisterClassLoader.invoke(aspectManager, new Object [] {loader}); 400 } 401 402 private static void printVariables() 403 { 404 Properties props = System.getProperties(); 405 Enumeration iter = props.keys(); 406 407 System.out.println("properties:"); 408 while (iter.hasMoreElements()) 409 { 410 Object key = iter.nextElement(); 411 System.out.println(key + "=" + props.get(key)); 412 System.out.println(); 413 } 414 } 415 416 private static ClassLoader newClassLoader() throws Exception { 417 URL classLocation = MemoryLeakTestCase.class.getProtectionDomain().getCodeSource().getLocation(); 419 StringTokenizer tokenString = new StringTokenizer (System.getProperty("java.class.path"),File.pathSeparator); 420 String pathIgnore = System.getProperty("path.ignore"); 421 if (pathIgnore==null) 422 { 423 pathIgnore = classLocation.toString(); 424 } else 425 { 426 System.out.println("pathIgnore=" + pathIgnore); 427 } 428 429 430 ArrayList urls = new ArrayList (); 431 while (tokenString.hasMoreElements()) 432 { 433 String value = tokenString.nextToken(); 434 URL itemLocation = new File (value).toURL(); 435 if (!itemLocation.equals(classLocation) && !itemLocation.toString().equals(pathIgnore)) 436 { 437 urls.add(itemLocation); 439 } 440 } 441 442 URL [] urlArray= (URL [])urls.toArray(new URL [urls.size()]); 443 444 ClassLoader masterClassLoader = URLClassLoader.newInstance(urlArray,null); 445 446 447 ClassLoader appClassLoader = URLClassLoader.newInstance(new URL [] {classLocation},masterClassLoader); 448 449 return appClassLoader; 450 } 451 452 453 private void undeploy(Class xmlLoader) throws Exception  454 { 455 456 String strurl = (String )AccessController.doPrivileged(new PrivilegedAction (){ 457 458 public Object run() 459 { 460 return System.getProperty("jboss.aop.path"); 461 } 462 463 }); 464 assertNotNull("Property jboss.aop.path should be defined",strurl); 466 strurl = strurl.replace('\\','/'); 467 URL url = new URL ("file:/" + strurl); 468 469 Method method = xmlLoader.getDeclaredMethod("undeployXML", new Class [] {URL .class}); 470 method.invoke(null, new Object [] {url}); 471 472 System.out.println("\n===================================================================="); 473 System.out.println("!!!! Undeployed " + url); 474 System.out.println("=====================================================================\n"); 475 476 } 478 479 } 480 | Popular Tags |