Memory leak of Configuration under Java 1.4, also EventManager

From: Mike Kienenberger (mkienen..mail.com)
Date: Thu Oct 18 2007 - 15:41:10 EDT

  • Next message: Andrus Adamchik: "Re: Memory leak of Configuration under Java 1.4, also EventManager"

    For what it's worth, there's a memory leak in Configuration. I doubt
    it will affect many people, but it was a significant contributor to
    the 1.5Gb memory requirements and 35 minutes when running my tests
    (now down to 400Mb in 25 minutes, although Velocity, StrutsTest, and
    personal memory leaks contributed some to this issue as well).

    The problem is that "new Thread()" without "thread.start()" under Java
    1.4 leaks memory.
    Every new instance of Configuration creates a new Thread() without
    starting it, and since this is an inner class for Configuration,
    configuration leaks. And that pretty much leaks the entire Cayenne
    runtime.

    All of my Cayenne tests create a new configuration, so this was a
    problem for me.

    Here's how I solved it in case anyone else has the same situation. I
    subclassed DefaultConfiguration (which is the superclass for all of my
    other classes) as follows, and then called the "clear()" method in my
    teardown().

    public class CleanableDefaultConfiguration extends DefaultConfiguration
    {
        public CleanableDefaultConfiguration()
        {
            super();
        }

        public CleanableDefaultConfiguration(String domainConfigurationName)
        {
            super(domainConfigurationName);
        }

        public void clear() {
            uninstallConfigurationShutdownHook();
            ((Thread)configurationShutdownHook).start();
            try {
                ((Thread)configurationShutdownHook).join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
            configurationShutdownHook = null;
            shutdown();
            this.setResourceLocator(null);
            sharedConfiguration = null;
        }
    }

    I also found issues with EventManager. There's no public interface
    to reset it. Here's what I ended up doing, but at some point there
    probably should be a way made to handle this with standard java code,
    and also shut down the EventManager.Dispatch threads. Currently
    those threads run until the JVM dies, and since they are inner classes
    to EventManager, that means EventManager and its referents can't be
    garbage collected.

    What I did was used reflection to clear out the subjects and
    eventQueue fields, which cuts down on the impact of the leak.

            // defaultManager is final -- can't reset it in java 1.4.
            EventManager defaultManager = EventManager.getDefaultManager();
            Field eventManagersubjectsField =
    EventManager.class.getDeclaredField("subjects");
            eventManagersubjectsField.setAccessible(true);
            eventManagersubjectsField.set(defaultManager,
    Collections.synchronizedMap(new WeakHashMap()));
            Field eventManagereventQueueField =
    EventManager.class.getDeclaredField("eventQueue");
            eventManagereventQueueField.setAccessible(true);
            eventManagereventQueueField.set(defaultManager,
    Collections.synchronizedList(new LinkedList()));

    Again, probably not an issue for most use cases, but with 800+
    integration tests, it's an issue for me.



    This archive was generated by hypermail 2.0.0 : Thu Oct 18 2007 - 15:41:49 EDT