Re: Memory leak of Configuration under Java 1.4, also EventManager

From: Mike Kienenberger (mkienen..mail.com)
Date: Thu Oct 18 2007 - 16:03:03 EDT

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

    I probably should have also mentioned that the new Thread() leak has
    been fixed for Java 1.5, although I'd expect you'd still need to deal
    with clearing sharedConfiguration somehow.

    On 10/18/07, Andrus Adamchik <andru..bjectstyle.org> wrote:
    > Hi Mike,
    >
    > Good stuff - we need to clean it up. I was not aware of the issue
    > with Configuration shutdown hook. Looking at the code, there is no
    > excuse for creating it eagerly for every instance. Let me actually
    > fix it now.
    >
    > Regarding EventManager, this is a known issue. There is an
    > EventManager.shutdown() method added in 3.0 (CAY-610) and we are
    > planning to weed out a few remaining references to the default static
    > EM (CAY-868) that leaks just a few threads.
    >
    > Andrus
    >
    >
    > On Oct 18, 2007, at 10:41 PM, Mike Kienenberger wrote:
    > > 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 - 16:03:37 EDT