This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 114210 - testEarProjectIsGCed fails
Summary: testEarProjectIsGCed fails
Status: RESOLVED FIXED
Alias: None
Product: serverplugins
Classification: Unclassified
Component: Sun Appserver 8 (show other bugs)
Version: 6.x
Hardware: All All
: P2 blocker (vote)
Assignee: _ pcw
URL:
Keywords: PERFORMANCE, TEST
Depends on:
Blocks:
 
Reported: 2007-08-30 10:05 UTC by Tomas Mysik
Modified: 2007-09-20 23:36 UTC (History)
2 users (show)

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tomas Mysik 2007-08-30 10:05:18 UTC
testEarProjectIsGCed:
      junit.framework.AssertionFailedError: project cannot be garbage collected:
private static final org.netbeans.modules.j2ee.dd.api.application.DDProvider 
org.netbeans.modules.j2ee.dd.api.application.DDProvider.ddProvider->
org.netbeans.modules.j2ee.dd.api.application.DDProvider@1a7d0c4-ddMap->
java.util.HashMap@5f177b-table->
[Ljava.util.HashMap$Entry;@4145f5-[6]->
java.util.HashMap$Entry@1ac05bc-value->
org.netbeans.modules.j2ee.dd.impl.application.ApplicationProxy@e5e84-listeners->
java.util.ArrayList@caba7f-elementData->
[Ljava.lang.Object;@1ce2867-[1]->
org.netbeans.modules.j2ee.sun.share.configbean.DescriptorListener@1c005eb-config->
org.netbeans.modules.j2ee.sun.share.configbean.SunONEDeploymentConfiguration@e5d2a3-module->
org.netbeans.modules.j2ee.deployment.devmodules.api.J2eeApplication@d210b2-impl->
org.netbeans.modules.j2ee.earproject.ProjectEar@1d8915a-project->
org.netbeans.modules.j2ee.earproject.EarProject@14afa30
        at junit.framework.Assert.fail(Assert.java:47)
Comment 1 Erno Mononen 2007-09-19 14:31:20 UTC
The fix is to use a weak listener for org.netbeans.modules.j2ee.sun.share.configbean.DescriptorListener when attaching 
it to the dd root (line 104 in DescriptorListener).
Comment 2 Vince Kraemer 2007-09-19 18:49:24 UTC
this looks like something related to the config area
Comment 3 Vince Kraemer 2007-09-19 18:50:46 UTC
this is probably a p2, too
Comment 4 _ pcw 2007-09-19 19:04:38 UTC
The fix is not as trivial as using a weak listener.

The code originally used a weak listener and then I spent a couple of days trying to figure out why the listeners would
randomly stop working mid stream -- because the proxy for standard DD would get garbage collected since there were no
strong references.

There is code already to disconnect the listener.  I will verify it is working and find out if that at fault.

Also, I cannot tell from description -- Was this path from the root set the ONLY piece of code holding the project?
Comment 5 _ pcw 2007-09-19 22:40:15 UTC
ConfigSupportImpl.dispose() in j2eeserver is only called when the target server is changed by the user.  It is NOT
called when the project is closed.

The listener in question cannot be a weak listener.  There are some common use cases ("open existing J2EE 1.4 project",
I think) where the listener is has the only outstanding reference to the DDProxy to which the listener was added.  If a
weak listener is used, the DDProxy is garbage collected when this state occurs and no subsequent change events will be
received by the server plugin.

Can j2eeserver module add a ProjectOpenedHook that calls J2eeModuleProvider.ConfigSupport.dispose() in the
projectClose() method (or some other mechanism that would be invoked on project close)?

As far as I can tell, server plugins are not able add a ProjectOpenedHook at all.

Comment 6 Petr Hejl 2007-09-20 18:39:13 UTC
Peter,
I inspected various solutions today (seems to me that OpenedProjectHooked would not be the right one). However I can't
see any scenario where the DDProxy could be accidentally collected (at least for the place we are discussing:
DescriptorListener). When the listener is added to the DDProxy it is stored in private variable too (DescriptorListener
itself is afaik always referenced from SunONEDeploymentConfiguration).

In fact the DDProxy objects are strongly referenced from DDProviders (I consider it memory leak). Only the DDProvider
for webapp uses weakreferences. Am I missing something? I really can't see any use case which could cause the garbage
collection (unwanted) of the DDProxy. If such scenario exists it would be nice to have a unit test for it before we
start fixing this issue.

I have tested that both fixes (weaklistener in DescriptorListener and weak values in DDProvider caches) pass the test.
Unfortunately there is no explanation in code of DDProvider why the weak references were commented out (causing the
memory leak).

Thanks for you opinions
P.
Comment 7 _ pcw 2007-09-20 19:46:51 UTC
See issue 110080 and issue 110081, specifically from my last comment (Jul 17 23:17:40):  

"The problem is simple: call DDProvider.getDDRoot(), add listeners, and (key point) don't hold a hard reference to proxy
WebApp.

The proxy WebApp is later garbage collected.  Then after that, when the web.xml editor is opened, web.xml's dataobject
asks for the proxy WebApp and a new one is created.  Thus expected events are never received because the listeners are
on the wrong (discarded) proxy."
Comment 8 _ pcw 2007-09-20 20:06:43 UTC
I have some more ideas on my side that would at least eliminate the project leak, even if the strong referenced listener
code stays.  I will try them out and if they work, check them in.
Comment 9 Petr Hejl 2007-09-20 20:15:31 UTC
I think I understand it better now, but you actually hold a strong reference in DescriptorListener. I think usage of the
WeakListener makes no difference:

    public void addListener(final RootInterface rootDD) {
        if(rootDD instanceof Webservices) {
            if(wsRootDD != null) {
                wsRootDD.removePropertyChangeListener(this);
            }
            wsRootDD = rootDD;
        } else {
            if(stdRootDD != null) {
                stdRootDD.removePropertyChangeListener(this);
            }
            stdRootDD = rootDD;
        }
        
        rootDD.addPropertyChangeListener(this);
        //could be used rootDD.addPropertyChangeListener(WeakListeners.propertyChange(this, rootDD));
    }
Comment 10 _ pcw 2007-09-20 23:14:35 UTC
Ah, the wonders of sleeping on a problem. (FWIW, I didn't like the projectClose() idea much either).

The old code that originally used a weak listener didn't hold a strong reference to the corresponding dd proxy (hence
110080)  The current does, so weaklistener will work fine and is the correct fix for this problem.

And you're right, the DDProviders that have strong references to the DDProxies (ejb ddapi, possibly ear and appclient as
well) are a memory leak (separate issue).