United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 7174718 [macosx] Regression in 7u6 b12: PopupFactory leaks DefaultFrames.
7174718 : [macosx] Regression in 7u6 b12: PopupFactory leaks DefaultFrames.

Details
Type:
Bug
Submit Date:
2012-06-06
Status:
Closed
Updated Date:
2012-07-20
Project Name:
JDK
Resolved Date:
2012-07-20
Component:
client-libs
OS:
os_x
Sub-Component:
java.awt
CPU:
x86,generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
7,7u6
Fixed Versions:
7u6

Related Reports
Backport:
Backport:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Relates:

Sub Tasks

Description
MacOS X 10.7.4 macmini4,1 and iMac

Run closed/javax/swing/Popup/DefaultFrameLeak/DefaultFrameLeak.java -- it will most probably pass on 7u6 b11 but always fail on b12 with 

java.lang.RuntimeException: FAIL: PopupFactory leaks DefaultFrames!
FAIL: Direct Popup use leaks DefaultFrames!

	at DefaultFrameLeak.onEDT1100(DefaultFrameLeak.java:176)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at SwingTestHelper.invoke(SwingTestHelper.java:625)
	at SwingTestHelper.access$800(SwingTestHelper.java:173)
	at SwingTestHelper$6.run(SwingTestHelper.java:609)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:241)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:701)
	at java.awt.EventQueue.access$000(EventQueue.java:102)
	at java.awt.EventQueue$3.run(EventQueue.java:662)
	at java.awt.EventQueue$3.run(EventQueue.java:660)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:671)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)

                                    

Comments
EVALUATION

So far I got zero success with the proposed solution. However, there's also another issue (7174713) which seems to be realted to a memory leak caused by 2D code that operates with CALayers. These two issues may be related.
                                     
2012-06-22
EVALUATION

Certainly, some improvements to the memory management code should be done. E.g. the CPlatformWindow is a CFRetainedResource. However, the CFRetain is currently called for the AWTWindow instance, whereas at the time of disposing a window, the corresponding CFRelease will be invoked for the NSWindow object. Also, the delegate object must be released manually (note that NSWindow setDelegate does NOT retain the delegate).

After making these changes I ensure that an instance of the AWTWindow class is in fact released and deallocated when Java calls removeNotify()/dispose() for a frame. And thus the javaPlatformWindow (which is a weak reference, but still) gets released as well. Also, the nsWindow property gets nil'ed, and hence doesn't hold the NSWindow object anymore.

However, the NSWindow object is still retained somewhere. I presume that 2D code holds a reference to the window. This code may also be responsible for creating a global ref to its Java Window object which prevents windows from being disposed completely. We should investigate this under 7174713.
                                     
2012-06-22
SUGGESTED FIX

--- old/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	2012-06-22 19:45:41.000000000 +0400
+++ new/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	2012-06-22 19:45:41.000000000 +0400
@@ -63,6 +63,7 @@
     private static native void nativeSetNSWindowSecurityWarningPositioning(long nsWindowPtr, double x, double y, float biasX, float biasY);
     private static native void nativeSetEnabled(long nsWindowPtr, boolean isEnabled);
     private static native void nativeSynthesizeMouseEnteredExitedEvents(long nsWindowPtr);
+    private static native void nativeDispose(long nsWindowPtr);
 
     private static native int nativeGetNSWindowDisplayID_AppKitThread(long nsWindowPtr);
 
@@ -423,6 +424,7 @@
         EventQueue.invokeLater(new Runnable() {
             public void run() {
                 contentView.dispose();
+                nativeDispose(getNSWindowPtr());
                 CPlatformWindow.super.dispose();
             }
         });
--- old/src/macosx/native/sun/awt/AWTWindow.m	2012-06-22 19:45:42.000000000 +0400
+++ new/src/macosx/native/sun/awt/AWTWindow.m	2012-06-22 19:45:42.000000000 +0400
@@ -228,6 +228,7 @@
     }
 
     if (self.nsWindow == nil) return nil; // no hope either
+    [self.nsWindow release]; // the property retains the object already
 
     self.isEnabled = YES;
     self.javaPlatformWindow = platformWindow;
@@ -677,9 +678,9 @@
                                                   styleBits:styleBits
                                                   frameRect:frameRect
                                                 contentView:contentView];
+        // the window is released is CPlatformWindow.nativeDispose()
 
-        if (window) CFRetain(window);
-        [window release]; // GC
+        if (window) CFRetain(window.nsWindow);
     }];
 
 JNF_COCOA_EXIT(env);
@@ -1158,5 +1159,26 @@
     }];
 
 JNF_COCOA_EXIT(env);
+}
+
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeDispose
+(JNIEnv *env, jclass clazz, jlong windowPtr)
+{
+JNF_COCOA_ENTER(env);
+
+    NSWindow *nsWindow = OBJC(windowPtr);
+    [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
+        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
+
+        // AWTWindow holds a reference to the NSWindow in its nsWindow
+        // property. Unsetting the delegate allows it to be deallocated
+        // which releases the reference. This, in turn, allows the window
+        // itself be deallocated.
+        [nsWindow setDelegate: nil];
+
+        [window release];
+    }];
+
+JNF_COCOA_EXIT(env);
 }
                                     
2012-06-22
EVALUATION

Actually, only one more call to release is missing: we allocate a new NSWindow object and assign it to a property. We must release it manually since the property retains it automatically. After this change the PopupFactory test passes.
                                     
2012-06-22
EVALUATION

This is a regression caused by 7149062.

Looks like the cause is that the nsWindow property is nil'ed in AWTWindow.dealloc. But dealloc is never called because the nsWindow holds a reference to the AWTWindow object (because the AWTWindow is set as a delegate for the nsWindow).
                                     
2012-06-20



Hardware and Software, Engineered to Work Together