- A Concurrent Affair - https://www.concurrentaffair.org -

Not a Memory Leak, But Not Finalized?

I’ve been trying to fix a memory leak in DrJava [1] today. I found the reproducible memory leak quite quickly: When I added the right margin line [2] feature, I added option listeners that change the color and position of the right margin line in the definitions panes when the preferences are changed. These listeners have kept references to the definitions panes they needed to update. Now I remove the listeners again when a pane is closed.

I still have a unit test failure, though, that happens about once or twice per ten runs. I don’t think it’s a memory leak, because when I dump the heap and run the Object Query Language (OQL) query

select d.creationContext.toString()
from edu.rice.cs.drjava.model.DefaultGlobalModel$ConcreteOpenDefDoc d

I get as result the following output:

java.lang.RuntimeException: new ConcreteOpenDefDoc
at edu.rice.cs.drjava.model.DefaultGlobalModel$ConcreteOpenDefDoc.(DefaultGlobalModel.java:467)
at edu.rice.cs.drjava.model.DefaultGlobalModel._createOpenDefinitionsDocument(DefaultGlobalModel.java:639)
at edu.rice.cs.drjava.model.DefaultGlobalModel._createOpenDefinitionsDocument(DefaultGlobalModel.java:102)
at edu.rice.cs.drjava.model.AbstractGlobalModel.newFile(AbstractGlobalModel.java:1151)
at edu.rice.cs.drjava.model.AbstractGlobalModel.newFile(AbstractGlobalModel.java:1141)
at edu.rice.cs.drjava.model.AbstractGlobalModel._ensureNotEmpty(AbstractGlobalModel.java:4121)
at edu.rice.cs.drjava.model.AbstractGlobalModel._init(AbstractGlobalModel.java:359)
at edu.rice.cs.drjava.model.AbstractGlobalModel.(AbstractGlobalModel.java:306)
at edu.rice.cs.drjava.model.DefaultGlobalModel.(DefaultGlobalModel.java:191)
at edu.rice.cs.drjava.ui.MainFrame$157.run(MainFrame.java:3014)
at edu.rice.cs.util.swing.Utilities.invokeAndWait(Utilities.java:70)
at edu.rice.cs.drjava.ui.MainFrame.(MainFrame.java:3006)
at edu.rice.cs.drjava.ui.DefinitionsPaneMemoryLeakTest$1.run(DefinitionsPaneMemoryLeakTest.java:81)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
----
java.lang.RuntimeException: new ConcreteOpenDefDoc
at edu.rice.cs.drjava.model.DefaultGlobalModel$ConcreteOpenDefDoc.(DefaultGlobalModel.java:467)
at edu.rice.cs.drjava.model.DefaultGlobalModel._createOpenDefinitionsDocument(DefaultGlobalModel.java:639)
at edu.rice.cs.drjava.model.DefaultGlobalModel._createOpenDefinitionsDocument(DefaultGlobalModel.java:102)
at edu.rice.cs.drjava.model.AbstractGlobalModel.newFile(AbstractGlobalModel.java:1151)
at edu.rice.cs.drjava.model.AbstractGlobalModel.newFile(AbstractGlobalModel.java:1175)
at edu.rice.cs.drjava.model.AbstractGlobalModel.newFile(AbstractGlobalModel.java:1183)
at edu.rice.cs.drjava.model.AbstractGlobalModel.closeFiles(AbstractGlobalModel.java:1979)
at edu.rice.cs.drjava.model.AbstractGlobalModel.closeAllFiles(AbstractGlobalModel.java:1944)
at edu.rice.cs.drjava.ui.DefinitionsPaneMemoryLeakTest$7.run(DefinitionsPaneMemoryLeakTest.java:197)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

This creation context stores the stack trace when the instance is created, and I can tell that one of these documents was created when DrJava was initially started, and the other after all documents have been closed. These aren’t the documents that need to be garbage-collected.

However, the test is based on finalization, and for one of the documents (not one of these two that still exist), the finalizer isn’t called. At least that’s what it seems like. It is garbage-collected, because otherwise it would appear in the query result.

I am also using the NetBeans memory leak test utilities [3], and they do not report a leak either. I’m starting to believe again that finalization is a fundamentally flawed way of checking for garbage collection.

[4] [5]Share [6]