alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Commons Beanutils example source code file (MemoryLeakTestCase.java)

This example Commons Beanutils source code file (MemoryLeakTestCase.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Commons Beanutils tags/keywords

a, beanclass, beanclass, big, classloader, classloader, classloaders, exception, method, net, network, object, string, string, util, weakreference, weakreference

The Commons Beanutils MemoryLeakTestCase.java source code

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
package org.apache.commons.beanutils.memoryleaktests;

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Locale;
import java.util.StringTokenizer;

import junit.framework.TestCase;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.MappedPropertyDescriptor;
import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.WrapDynaBean;
import org.apache.commons.beanutils.WrapDynaClass;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.locale.LocaleBeanUtilsBean;
import org.apache.commons.beanutils.locale.LocaleConvertUtils;
import org.apache.commons.beanutils.locale.converters.IntegerLocaleConverter;

/**
 * Test BeanUtils memory leaks.
 * 
 * See https://issues.apache.org/jira/browse/BEANUTILS-291
 * 
 * @author Clebert Suconic
 */
public class MemoryLeakTestCase extends TestCase {

    /**
     * Tests that PropertyUtilsBean's descriptorsCache doesn't cause a memory leak.
     */
    public void testPropertyUtilsBean_descriptorsCache_memoryLeak() throws Exception {
        if (isPre15JVM()) {
            return;
        }

        // Clear All BeanUtils caches before the test
        clearAllBeanUtilsCaches();

        String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.SomePojo";

        // The classLoader will go away only when these following variables are released
        ClassLoader loader = newClassLoader();
        Class beanClass    = loader.loadClass(className);
        Object bean        = beanClass.newInstance();
        // -----------------------------------------------------------------------------

        WeakReference someRef = new WeakReference(loader);

        // Sanity checks only
        assertNotNull("ClassLoader is null", loader);
        assertNotNull("BeanClass is null", beanClass);
        assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader());
        assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader);

        // if you comment the following line, the testcase will work, and the ClassLoader will be released.
        // That proves that nothing is wrong with the test, and PropertyUtils is holding a reference
        assertEquals("initialValue", PropertyUtils.getProperty(bean, "name"));

        // this should make the reference go away.
        loader    = null;
        beanClass = null;
        bean      = null;

        forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */

        if (someRef.get() != null) {
            profilerLeakReport("PropertyUtilsBean descriptorsCache", className);
        }

        // if everything is fine, this will be null
        assertNull("PropertyUtilsBean is holding a reference to the classLoader", someRef.get());

        // Clear All BeanUtils caches after the test
        clearAllBeanUtilsCaches();
    }

    /**
     * Tests that PropertyUtilsBean's mappedDescriptorsCache doesn't cause a memory leak.
     */
    public void testPropertyUtilsBean_mappedDescriptorsCache_memoryLeak() throws Exception {
        if (isPre15JVM()) {
            return;
        }

        // Clear All BeanUtils caches before the test
        clearAllBeanUtilsCaches();

        String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.SomeMappedPojo";

        // The classLoader will go away only when these following variables are released
        ClassLoader loader = newClassLoader();
        Class beanClass    = loader.loadClass(className);
        Object bean        = beanClass.newInstance();
        // -----------------------------------------------------------------------------

        WeakReference someRef = new WeakReference(loader);

        // Sanity checks only
        assertNotNull("ClassLoader is null", loader);
        assertNotNull("BeanClass is null", beanClass);
        assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader());
        assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader);

        // if you comment the following three lines, the testcase will work, and the ClassLoader will be released.
        // That proves that nothing is wrong with the test, and PropertyUtils is holding a reference
        assertEquals("Second Value", PropertyUtils.getProperty(bean, "mappedProperty(Second Key)"));
        PropertyUtils.setProperty(bean, "mappedProperty(Second Key)", "New Second Value");
        assertEquals("New Second Value", PropertyUtils.getProperty(bean, "mappedProperty(Second Key)"));

        // this should make the reference go away.
        loader = null;
        beanClass = null;
        bean = null;

        // PropertyUtilsBean uses the MethodUtils's method cache for mapped properties.
        // Uncomment the following line to check this is not just a repeat of that memory leak.
        // MethodUtils.clearCache();
        
        forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */

        if (someRef.get() != null) {
            profilerLeakReport("PropertyUtilsBean mappedDescriptorsCache", className);
        }

        // if everything is fine, this will be null
        assertNull("PropertyUtilsBean is holding a reference to the classLoader", someRef.get());

        // Clear All BeanUtils caches after the test
        clearAllBeanUtilsCaches();
    }

    /**
     * Tests that MappedPropertyDescriptor can re-create the Method reference after it
     * has been garbage collected.
     */
    public void testMappedPropertyDescriptor_MappedMethodReference1() throws Exception {

        // Clear All BeanUtils caches before the test
        clearAllBeanUtilsCaches();

        String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.SomeMappedPojo";
        ClassLoader loader = newClassLoader();
        Class beanClass    = loader.loadClass(className);
        Object bean        = beanClass.newInstance();
        // -----------------------------------------------------------------------------

        // Sanity checks only
        assertNotNull("ClassLoader is null", loader);
        assertNotNull("BeanClass is null", beanClass);
        assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader());
        assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader);

        MappedPropertyDescriptor descriptor = new MappedPropertyDescriptor("mappedProperty", beanClass);
        assertNotNull("1-Read Method null", descriptor.getMappedReadMethod());
        assertNotNull("1-Write Method null", descriptor.getMappedWriteMethod());
        assertEquals("1-Read Method name", "getMappedProperty", descriptor.getMappedReadMethod().getName());
        assertEquals("1-Read Write name", "setMappedProperty", descriptor.getMappedWriteMethod().getName());

        forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */

        // The aim of this test is to check the functinality in MappedPropertyDescriptor which
        // re-creates the Method references after they have been garbage collected. However theres no
        // way of knowing the method references were garbage collected and that code was run, except by
        // un-commeting the System.out statement in MappedPropertyDescriptor's MappedMethodReference's
        // get() method.

        assertNotNull("1-Read Method null", descriptor.getMappedReadMethod());
        assertNotNull("1-Write Method null", descriptor.getMappedWriteMethod());
        assertEquals("1-Read Method name", "getMappedProperty", descriptor.getMappedReadMethod().getName());
        assertEquals("1-Read Write name", "setMappedProperty", descriptor.getMappedWriteMethod().getName());

        // Clear All BeanUtils caches after the test
        clearAllBeanUtilsCaches();
    }

    /**
     * Tests that MappedPropertyDescriptor can re-create the Method reference after it
     * has been garbage collected.
     */
    public void testMappedPropertyDescriptor_MappedMethodReference2() throws Exception {

        // Clear All BeanUtils caches before the test
        clearAllBeanUtilsCaches();

        String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.SomeMappedPojo";
        ClassLoader loader = newClassLoader();
        Class beanClass    = loader.loadClass(className);
        Object bean        = beanClass.newInstance();
        // -----------------------------------------------------------------------------

        // Sanity checks only
        assertNotNull("ClassLoader is null", loader);
        assertNotNull("BeanClass is null", beanClass);
        assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader());
        assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader);

        MappedPropertyDescriptor descriptor = new MappedPropertyDescriptor("mappedProperty", beanClass);
        assertNotNull("1-Read Method null", descriptor.getMappedReadMethod());
        assertNotNull("1-Write Method null", descriptor.getMappedWriteMethod());
        assertEquals("1-Read Method name", "getMappedProperty", descriptor.getMappedReadMethod().getName());
        assertEquals("1-Read Write name", "setMappedProperty", descriptor.getMappedWriteMethod().getName());

        // this should make the reference go away.
        loader = null;
        beanClass = null;
        bean = null;

        forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */

        // The aim of this test is to check the functinality in MappedPropertyDescriptor which
        // re-creates the Method references after they have been garbage collected. However theres no
        // way of knowing the method references were garbage collected and that code was run, except by
        // un-commeting the System.out statement in MappedPropertyDescriptor's MappedMethodReference's
        // get() method.

        assertNotNull("1-Read Method null", descriptor.getMappedReadMethod());
        assertNotNull("1-Write Method null", descriptor.getMappedWriteMethod());
        assertEquals("1-Read Method name", "getMappedProperty", descriptor.getMappedReadMethod().getName());
        assertEquals("1-Read Write name", "setMappedProperty", descriptor.getMappedWriteMethod().getName());

        // Clear All BeanUtils caches after the test
        clearAllBeanUtilsCaches();
    }

    /**
     * Tests that MethodUtils's cache doesn't cause a memory leak.
     */
    public void testMethodUtils_cache_memoryLeak() throws Exception {

        // Clear All BeanUtils caches before the test
        clearAllBeanUtilsCaches();

        String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.SomePojo";

        // The classLoader will go away only when these following variables are released
        ClassLoader loader = newClassLoader();
        Class beanClass    = loader.loadClass(className);
        Object bean        = beanClass.newInstance();
        // -----------------------------------------------------------------------------

        WeakReference someRef = new WeakReference(loader);

        // Sanity checks only
        assertNotNull("ClassLoader is null", loader);
        assertNotNull("BeanClass is null", beanClass);
        assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader());
        assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader);

        // if you comment the following line, the testcase will work, and the ClassLoader will be released.
        // That proves that nothing is wrong with the test, and MethodUtils is holding a reference
        assertEquals("initialValue", MethodUtils.invokeExactMethod(bean, "getName", new Object[0]));

        // this should make the reference go away.
        loader    = null;
        beanClass = null;
        bean      = null;

        forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */

        if (someRef.get() != null) {
            profilerLeakReport("MethodUtils cache", className);
        }

        // if everything is fine, this will be null
        assertNull("MethodUtils is holding a reference to the classLoader", someRef.get());

        // Clear All BeanUtils caches after the test
        clearAllBeanUtilsCaches();
    }

    /**
     * Tests that WrapDynaClass's dynaClasses doesn't cause a memory leak.
     */
    public void testWrapDynaClass_dynaClasses_memoryLeak() throws Exception {
        if (isPre15JVM()) {
            return;
        }

        // Clear All BeanUtils caches before the test
        clearAllBeanUtilsCaches();

        String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.SomePojo";

        // The classLoader will go away only when these following variables are released
        ClassLoader loader = newClassLoader();
        Class beanClass    = loader.loadClass(className);
        Object bean        = beanClass.newInstance();
        WrapDynaBean wrapDynaBean = new WrapDynaBean(bean);
        // -----------------------------------------------------------------------------

        WeakReference someRef = new WeakReference(loader);

        // Sanity checks only
        assertNotNull("ClassLoader is null", loader);
        assertNotNull("BeanClass is null", beanClass);
        assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader());
        assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader);

        // if you comment the following line, the testcase will work, and the ClassLoader will be released.
        // That proves that nothing is wrong with the test, and WrapDynaClass is holding a reference
        assertEquals("initialValue", wrapDynaBean.get("name"));

        // this should make the reference go away.
        loader       = null;
        beanClass    = null;
        bean         = null;
        wrapDynaBean = null;

        // Wrap Dyna Class uses the PropertyUtilsBean's decriptor caches.
        // Uncomment the following line to check this is not just a repeat of that memory leak.
        // BeanUtilsBean.getInstance().getPropertyUtils().clearDescriptors();

        forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */

        if (someRef.get() != null) {
            profilerLeakReport("WrapDynaClass dynaClasses", className);
        }

        // if everything is fine, this will be null
        assertNull("WrapDynaClass is holding a reference to the classLoader", someRef.get());

        // Clear All BeanUtils caches after the test
        clearAllBeanUtilsCaches();
    }

    /**
     * Tests that ConvertUtilsBean's converters doesn't cause a memory leak.
     */
    public void testConvertUtilsBean_converters_memoryLeak() throws Exception {

        // Clear All BeanUtils caches before the test
        clearAllBeanUtilsCaches();

        String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.CustomInteger";

        // The classLoader will go away only when these following variables are released
        ClassLoader loader = newClassLoader();
        Class beanClass    = loader.loadClass(className);
        Object bean        = beanClass.newInstance();
        // -----------------------------------------------------------------------------

        WeakReference someRef = new WeakReference(loader);

        // Sanity checks only
        assertNotNull("ClassLoader is null", loader);
        assertNotNull("BeanClass is null", beanClass);
        assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader());
        assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader);

        // if you comment the following two lines, the testcase will work, and the ClassLoader will be released.
        // That proves that nothing is wrong with the test, and ConvertUtilsBean is holding a reference
        ConvertUtils.register(new IntegerConverter(), beanClass);
        assertEquals("12345", ConvertUtils.convert(bean, String.class));

        // this should make the reference go away.
        loader    = null;
        beanClass = null;
        bean      = null;

        forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */

        if (someRef.get() != null) {
            profilerLeakReport("ConvertUtilsBean converters", className);
        }

        // if everything is fine, this will be null
        assertNull("ConvertUtilsBean is holding a reference to the classLoader", someRef.get());

        // Clear All BeanUtils caches after the test
        clearAllBeanUtilsCaches();
    }

    /**
     * Tests that LocaleConvertUtilsBean's converters doesn't cause a memory leak.
     */
    public void testLocaleConvertUtilsBean_converters_memoryLeak() throws Exception {

        // Clear All BeanUtils caches before the test
        clearAllBeanUtilsCaches();

        String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.CustomInteger";

        // The classLoader will go away only when these following variables are released
        ClassLoader loader = newClassLoader();
        Class beanClass    = loader.loadClass(className);
        Object bean        = beanClass.newInstance();
        // -----------------------------------------------------------------------------

        WeakReference someRef = new WeakReference(loader);

        // Sanity checks only
        assertNotNull("ClassLoader is null", loader);
        assertNotNull("BeanClass is null", beanClass);
        assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader());
        assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader);

        // if you comment the following two lines, the testcase will work, and the ClassLoader will be released.
        // That proves that nothing is wrong with the test, and LocaleConvertUtilsBean is holding a reference
        LocaleConvertUtils.register(new IntegerLocaleConverter(Locale.US, false), beanClass, Locale.US);
        assertEquals(new Integer(12345), LocaleConvertUtils.convert(bean.toString(), beanClass, Locale.US, "#,###"));

        // this should make the reference go away.
        loader    = null;
        beanClass = null;
        bean      = null;

        forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */

        if (someRef.get() != null) {
            profilerLeakReport("LocaleConvertUtilsBean converters", className);
        }

        // if everything is fine, this will be null
        assertNull("LocaleConvertUtilsBean is holding a reference to the classLoader", someRef.get());

        // Clear All BeanUtils caches after the test
        clearAllBeanUtilsCaches();
    }

    /**
     * Clear all the BeanUtils Caches manually.
     *
     * This is probably overkill, but since we're dealing with static caches
     * it seems sensible to ensure that all test cases start with a clean sheet.
     */
    private void clearAllBeanUtilsCaches() {

        // Clear BeanUtilsBean's PropertyUtilsBean descriptor caches
        BeanUtilsBean.getInstance().getPropertyUtils().clearDescriptors();

        // Clear LocaleBeanUtilsBean's PropertyUtilsBean descriptor caches
        LocaleBeanUtilsBean.getInstance().getPropertyUtils().clearDescriptors();

        // Clear MethodUtils's method cache
        MethodUtils.clearCache();

        // Clear WrapDynaClass cache
        WrapDynaClass.clear();

        // replace the existing BeanUtilsBean instance for the current class loader with a new, clean instance
        BeanUtilsBean.setInstance(new BeanUtilsBean());

        // replace the existing LocaleBeanUtilsBean instance for the current class loader with a new, clean instance
        LocaleBeanUtilsBean.setInstance(new LocaleBeanUtilsBean());
    }

    /**
     * Try to force the garbage collector to run by filling up memory and calling System.gc().
     */
    private void forceGarbageCollection() throws Exception {
        // Fill up memory
        SoftReference ref = new SoftReference(new Object());
        int count = 0;
        while(ref.get() != null && count++ < 5) {
            java.util.ArrayList list = new java.util.ArrayList();
            try {
                long i = 0;
                while (true && ref.get() != null) {
                    list.add("A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String " + (i++));
                }
            } catch (Throwable ignored) {
            }
            list.clear();
            list = null;
            // System.out.println("Count " + count + " : " + getMemoryStats());
            System.gc(); 
            Thread.sleep(1000);
        }
        // System.out.println("After GC: " + getMemoryStats());
        
        if (ref.get() != null) {
            throw new IllegalStateException("Your JVM is not releasing SoftReference, try running the testcase with less memory (-Xmx)");
        }
    }

    /**
     * Create a new class loader instance.
     */
    private static URLClassLoader newClassLoader() throws MalformedURLException {

        String dataFilePath = MemoryLeakTestCase.class.getResource("pojotests").getFile();
        //System.out.println("dataFilePath: " + dataFilePath);
        String location = "file://" + dataFilePath.substring(0,dataFilePath.length()-"org.apache.commons.beanutils.memoryleaktests.pojotests".length());
        //System.out.println("location: " + location);

        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();
        //System.out.println("classlocation: " + classLocation);

        URLClassLoader theLoader = URLClassLoader.newInstance(new URL[]{new URL(classLocation)},null);
        return theLoader;
    }

    /**
     * Produce a profiler report about where the leaks are.
     *
     * This requires JBoss's profiler be installed, see:
     *     http://labs.jboss.com/jbossprofiler/
     *
     * @param className The name of the class to profile
     */
    private void profilerLeakReport(String test, String className) {
       /*
        * If you want a report about where the leaks are... uncomment this,
        * add jboss-profiler.jvmti.jar and jboss-commons.jar (for org.jboss.loggin).
        * You will then have a report for where the references are.
        System.out.println(" ----------------" + test + " START ----------------");
        org.jboss.profiler.jvmti.JVMTIInterface jvmti = new org.jboss.profiler.jvmti.JVMTIInterface();
        System.out.println(jvmti.exploreClassReferences(className, 8, true, true, true, false, false));
        System.out.println(" ----------------" + test + " END ------------------");
        */
    }

    /**
     * Test for JDK 1.5
     */
    private boolean isPre15JVM() {
        String version = System.getProperty("java.specification.version");
        StringTokenizer tokenizer = new StringTokenizer(version,".");
        if (tokenizer.nextToken().equals("1")) {
            String minorVersion = tokenizer.nextToken();
            if (minorVersion.equals("0")) return true;
            if (minorVersion.equals("1")) return true;
            if (minorVersion.equals("2")) return true;
            if (minorVersion.equals("3")) return true;
            if (minorVersion.equals("4")) return true;
        }
        return false;
    }

    /**
     * Get the total, free, used memory stats.
     * @return the total, free, used memory stats
     */
    private String getMemoryStats() {
        java.text.DecimalFormat fmt = new java.text.DecimalFormat("#,##0");
        Runtime runtime = Runtime.getRuntime();
        long free = runtime.freeMemory() / 1024;
        long total = runtime.totalMemory() / 1024;
        long used = total - free;
        return "MEMORY - Total: " + fmt.format(total) + "k " + "Used: "
                + fmt.format(used) + "k " + "Free: "
                + fmt.format(free) + "k";
    }
}

Other Commons Beanutils examples (source code examples)

Here is a short list of links related to this Commons Beanutils MemoryLeakTestCase.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.