cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mike Kienenberger" <mkien...@gmail.com>
Subject Memory leak of Configuration under Java 1.4, also EventManager
Date Thu, 18 Oct 2007 19:41:10 GMT
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.

Mime
View raw message