Package org.jboss.serial.memory

Source Code of org.jboss.serial.memory.MemoryLeakTestCase$HierarchicalClassLoader

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

package org.jboss.serial.memory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

import junit.framework.TestCase;

import org.jboss.profiler.jvmti.JVMTIInterface;
import org.jboss.serial.classmetamodel.ClassMetaData;
import org.jboss.serial.classmetamodel.ClassMetamodelFactory;
import org.jboss.serial.io.JBossObjectInputStream;
import org.jboss.serial.io.JBossObjectOutputStream;
import org.jboss.serial.util.TestUtil;

/**
* This class requires -agentlib:jbossAgent on JVM arguments on the JVM for working properly
*
* It's also needed to set classes.location property as we need the classLoader finding this.
* @author csuconic
*
*/
public class MemoryLeakTestCase extends TestCase {

  private static final String CLASS_NAME = "org.jboss.serial.memory.test.SomePojo";

  private static JVMTIInterface jvmtiInterface = null;

  static
  {
    JVMTIInterface jvmti = new JVMTIInterface();
    if (jvmti.isActive())
     
    {
      jvmtiInterface = new JVMTIInterface();

    }
  }

  public void testValidate() throws Exception
  {
    if (jvmtiInterface==null)
    {
      System.out.println("testValidate is only valid when using profiler");
      return;
    }
    try
    {
     
      URLClassLoader theLoader = newClassLoader();

      Class testClass = theLoader.loadClass(CLASS_NAME);
     
      //testClass=null;
     
      jvmtiInterface.forceGC();
      assertNotNull("Class should still have a reference",jvmtiInterface.getClassByName(CLASS_NAME));
     
      Object someInstance = testClass.newInstance();
      WeakReference weakReference = new WeakReference(someInstance);
      someInstance=null;
     
      // 2 - because there is a static reference on the POJO itself
      assertEquals(2,jvmtiInterface.getAllObjects(testClass).length);

      jvmtiInterface.forceGC();
     
      assertTrue(weakReference.get()==null);
      // there is a static reference on the POJO itself
      assertEquals(1,jvmtiInterface.getAllObjects(testClass).length);

     
      testClass=null;
      theLoader=null;
     
      jvmtiInterface.forceGC();

      Class clazz = jvmtiInterface.getClassByName(CLASS_NAME);
      assertNull("Class should been unloaded by definition",clazz);

      theLoader = newClassLoader();
      WeakReference softReference = new WeakReference (theLoader.loadClass(CLASS_NAME));
      Class strongReference = (Class)softReference.get();
      theLoader=null;
   
      jvmtiInterface.forceGC();
      assertNotNull(jvmtiInterface.getClassByName(CLASS_NAME));
      assertNotNull(softReference.get());
      jvmtiInterface.forceGC();
      assertNotNull(softReference.get());

      jvmtiInterface.forceGC();
      assertNotNull(softReference.get());

      jvmtiInterface.forceGC();
      assertNotNull(softReference.get());

      jvmtiInterface.forceGC();
      assertNotNull(softReference.get());

      strongReference=null;
     
      jvmtiInterface.forceGC();
     
      assertNull(jvmtiInterface.getClassByName(CLASS_NAME));

     
     
    }
    catch (Exception e)
    {
      e.printStackTrace();
      throw e;
    }
  }


  private static URLClassLoader newClassLoader() throws MalformedURLException {
   
        String dataFilePath = MemoryLeakTestCase.class.getResource("test").getFile();
        String location = "file://" + dataFilePath.substring(0,dataFilePath.length()-"org.jboss.serial.memory.test".length());
       
        StringBuffer newString = new StringBuffer();
        for (int i=0;i<location.length();i++)
        {
          if (location.charAt(i)=='\\')
          {
            newString.append("/");
          }
          else
          {
            newString.append(location.charAt(i));
          }
        }
        String classLocation = newString.toString();
       
   
    URLClassLoader theLoader = URLClassLoader.newInstance(new URL[]{new URL(classLocation)},null);
    return theLoader;
  }
 
  static class HierarchicalClassLoader extends ClassLoader
  {
    public HierarchicalClassLoader(ClassLoader parent)
    {
      super(parent);
    }
  }

  private static ClassLoader newHierarchicalClassLoader(ClassLoader parent) throws MalformedURLException {

    return new HierarchicalClassLoader(parent);
  }
 

  public void testMetaDataOnly() throws Exception
  {
    ClassMetamodelFactory.clear();

    int count=0;
    ArrayList classes = new ArrayList();
    try
    {
      for (count=0;count<10;count++)
      {
        URLClassLoader loader = newClassLoader();
        Class testClass = loader.loadClass(CLASS_NAME);
        testClass.newInstance();
        ClassMetamodelFactory.getClassMetaData(testClass,true);
        classes.add(testClass);
        //testClass=null;
        //loader=null;
      }
    }
    catch (OutOfMemoryError e)
    {
      e.printStackTrace();
    }
   
    System.out.println("Loaded " + count + " total");
    classes.clear();
    System.out.println("cache size = " + ClassMetamodelFactory.getCache().size());
    forceOutOfMemoryError();
    forceGC();
    System.out.println("cache size (after GC)= " + ClassMetamodelFactory.getCache().size());
   
    if (jvmtiInterface!=null)
    {
      Class referenceClass = jvmtiInterface.getClassByName(CLASS_NAME);
     
      if (referenceClass!=null)
      {
        printReferences(jvmtiInterface,referenceClass);
        jvmtiInterface.heapSnapshot("classFactoryModel","mem");
        fail("Class " + CLASS_NAME + " should be unloaded");
      }
    }
    else
    {
      assertEquals(0,ClassMetamodelFactory.getCache().size());
    }
   
  }


  private void forceGC() throws InterruptedException {
    if (jvmtiInterface!=null)
    {
      jvmtiInterface.forceGC();
    }
    else
    {
      System.gc();
      Thread.sleep(1000);
    }
  }
 
  public void testSerialization() throws Exception
  {
    ClassMetamodelFactory.clear();
    URLClassLoader loader = newClassLoader();

    Class testClass = loader.loadClass(CLASS_NAME);
    Object someInstance = testClass.newInstance();
   
   
    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
    JBossObjectOutputStream objOut = new JBossObjectOutputStream(byteOut);
   
    objOut.writeObject(someInstance);
    objOut.flush();
   
    JBossObjectInputStream objInput = new JBossObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()),loader);
    Object newObject = objInput.readObject();

    forceGC();
    System.out.println("Size = " + ClassMetamodelFactory.getCache().size());
   
   
    if (jvmtiInterface!=null)
    {
      // there is a static reference on the POJO itself
      assertEquals(3,jvmtiInterface.getAllObjects(testClass).length);
    }

    loader=null;
    testClass=null;
    someInstance=null;
    newObject=null;
    objOut=null;
    objInput=null;

    forceOutOfMemoryError();
    forceGC();
    System.out.println("Size = " + ClassMetamodelFactory.getCache().size());
   
    if (jvmtiInterface!=null)
    {
      Class clazz = jvmtiInterface.getClassByName(CLASS_NAME);
      if (clazz!=null)
      {
        Object obj = clazz;
        Object[] referenceHolders = printReferences(jvmtiInterface, obj);
       
        // You can use JBossProfiler to analyze this snapshot
        jvmtiInterface.heapSnapshot("./memory-tst","mem");
      }
      assertNull("Class org.jboss.serial.memory.SomePojo should been unloaded already",clazz);
    }
    else
    {
      assertEquals(0,ClassMetamodelFactory.getCache().size());
    }
     
  }

  public void testSerializationWithCrossedClassLoaders() throws Exception
  {
    ClassMetamodelFactory.clear();
    Class testClass = null;
    URLClassLoader loader1 = null;
    for (int i=0;i<4;i++)
    {
      loader1 = newClassLoader();
     
      System.out.println("Operation " + i);
      ClassLoader loader2 = newHierarchicalClassLoader(loader1);
      testClass = loader1.loadClass(CLASS_NAME);
      Class testClass2 = loader2.loadClass("org.jboss.serial.memory.test.SomePojoCross");
     
      Object childObject = testClass.newInstance();
      Object rootObject = testClass2.newInstance();
 
      Method method = testClass2.getMethod("setOtherPojo",new Class[]{Object.class});
      method.invoke(rootObject,new Object[]{childObject});
     
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      JBossObjectOutputStream objOut = new JBossObjectOutputStream(byteOut);
     
      objOut.writeObject(rootObject);
      objOut.flush();
     
      loader1 = null;
      testClass=null;
      childObject = null;
      forceOutOfMemoryError();
      forceGC();
     
      JBossObjectInputStream objInput = new JBossObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()),loader2);
      Object newObject = objInput.readObject();
    }
    testClass=null;
    loader1=null;
    forceOutOfMemoryError();
    forceGC();
    assertEquals(0,ClassMetamodelFactory.getCache().size());
     
  }

  // simulates cross ClassLoader conflicts on the cache
  public void testSerializationCrossLoaderClearingCache() throws Exception
  {
    ClassMetamodelFactory.clear();
    Class testClass = null;
    URLClassLoader loader = newClassLoader();
    for (int i=0;i<10;i++)
    {
      forceCrossedClassLoaderRelease();
      System.out.println("Operation " + i);
      ClassLoader loader2 = newHierarchicalClassLoader(loader);
      testClass = loader.loadClass(CLASS_NAME);
      Class testClass2 = loader2.loadClass("org.jboss.serial.memory.test.SomePojoCross");
     
      Object childObject = testClass.newInstance();
      Object rootObject = testClass2.newInstance();
 
      Method method = testClass2.getMethod("setOtherPojo",new Class[]{Object.class});
      method.invoke(rootObject,new Object[]{childObject});
     
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      JBossObjectOutputStream objOut = new JBossObjectOutputStream(byteOut);
     
      objOut.writeObject(rootObject);
      objOut.flush();

      forceCrossedClassLoaderRelease();
     
      JBossObjectInputStream objInput = new JBossObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()),loader);
      Object newObject = objInput.readObject();
    }
    testClass=null;
    loader=null;
    forceOutOfMemoryError();
    forceGC();
    assertEquals(0,ClassMetamodelFactory.getCache().size());
     
  }


  public static void forceCrossedClassLoaderRelease() {
    Iterator valueIterator = ClassMetamodelFactory.getCache().values().iterator();
    while (valueIterator.hasNext())
    {
      Map map = (Map)valueIterator.next();
      Iterator classesIterator = map.values().iterator();
      while (classesIterator.hasNext())
      {
        ClassMetaData metaData = (ClassMetaData)classesIterator.next();
        metaData.setClazz(null);
      }
    }
  }

  // Just combining possibilities
  public final void testSerializationWithCrossedClassLoadersInverted() throws Exception
  {
    ClassMetamodelFactory.clear();
    Class testClass = null;
    URLClassLoader loader = newClassLoader();
    for (int i=0;i<10;i++)
    {
      System.out.println("Operation " + i);
      ClassLoader loader2 = newHierarchicalClassLoader(loader);
      testClass = loader2.loadClass(CLASS_NAME);
      Class testClass2 = loader.loadClass("org.jboss.serial.memory.test.SomePojoCross");
     
      Object childObject = testClass.newInstance();
      Object rootObject = testClass2.newInstance();
 
      Method method = testClass2.getMethod("setOtherPojo",new Class[]{Object.class});
      method.invoke(rootObject,new Object[]{childObject});
     
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      JBossObjectOutputStream objOut = new JBossObjectOutputStream(byteOut);
     
      objOut.writeObject(rootObject);
      objOut.flush();
     
      JBossObjectInputStream objInput = new JBossObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()),loader);
      Object newObject = objInput.readObject();
    }
    testClass=null;
    loader=null;
    forceOutOfMemoryError();
    forceGC();
    assertEquals(0,ClassMetamodelFactory.getCache().size());
     
  }

  /*  This is just an example on how we would validate JavaSerialization. You can uncoment this to perform some tests.
  public void testJavaSerialization() throws Exception
  {
    if (newjvmtiInterface!=null)
    {
      System.out.println("testValidate is only valid when using profiler");
      return;
    }
    try
    {
      serializeJava(jvmtiInterface,CLASS_NAME);
      forceOutOfMemoryError();
      serializeJava(jvmtiInterface,CLASS_NAME + "2");

      ClassMetamodelFactory.clear();

      forceOutOfMemoryError();
     
      Class clazz = jvmtiInterface.getClassByName(CLASS_NAME);
      if (clazz!=null)
      {
        Object obj = clazz;
        Object[] referenceHolders = printReferences(jvmtiInterface, obj);
       
        // You can use JBossProfiler to analyze this snapshot
        jvmtiInterface.heapSnapshot("./memory-tst","mem");
      }
      assertNull("Class org.jboss.serial.memory.SomePojo should been unloaded already",clazz);
     
    }
    catch (Exception e)
    {
      e.printStackTrace();
      Class clazz = jvmtiInterface.getClassByName(CLASS_NAME);
      if (clazz!=null)
      {
        Object obj = clazz;
        Object[] referenceHolders = printReferences(jvmtiInterface, obj);
       
        // You can use JBossProfiler to analyze this snapshot
        jvmtiInterface.heapSnapshot("./memory-ex2","mem");
      }
      System.out.println("Class org.jboss.serial.memory.SomePojo should been unloaded already" + clazz);
      throw e;
    }
  } */
 
 
  private static void forceOutOfMemoryError() {
    TestUtil.forceSoftReferences();
  }


 
  private Object[] printReferences(JVMTIInterface jvmtiInterface, Object obj) {
    Object referenceHolders[] = jvmtiInterface.getReferenceHolders(new Object[]{obj});

    System.out.println("References for " + obj);
    for (int i=0;i<referenceHolders.length;i++)
    {
      System.out.println("Reference[" + i + "]=" + referenceHolders[i].getClass().getName());
    }
   
    return referenceHolders;
  }


 
}
TOP

Related Classes of org.jboss.serial.memory.MemoryLeakTestCase$HierarchicalClassLoader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.