Hello.
My name is Jaroslav Tulach and I working on NetBeans. Recently I started to 
fight with memory leaks by writing some automated tests to verify that some 
sequence of actions does not leave a memory behind.

I think the tests are paying off, we managed to fix many leaks in NetBeans 
code. However now we are facing an unsolvable problem: there are some 
(temporary) leaks in AWT and Swing code which cause our tests to randomly 
fail.

We tried to workaround the problem (by opening new unrelated windows, or using 
reflection to clean well known references), but so far our solutions are 
fragile and the test continue to fail in new, inventive ways (for example 
https://netbeans.org/bugzilla/show_bug.cgi?id=197905).

It would be much easier if we could eliminate the (temporary) memory leaks in 
AWT/Swing code. I am attaching a patch that uses WeakReference instead of 
strong one that would fix one of our failing test.

What it would take to accept my patch? Thanks for your advice and help.
-jt

diff -r 39de8937c1d8 src/share/classes/java/awt/KeyboardFocusManager.java
--- a/src/share/classes/java/awt/KeyboardFocusManager.java	Thu Jun 02 13:38:28 2011 -0700
+++ b/src/share/classes/java/awt/KeyboardFocusManager.java	Wed Jul 20 08:50:25 2011 +0200
@@ -38,6 +38,7 @@
 import java.beans.VetoableChangeListener;
 import java.beans.VetoableChangeSupport;
 
+import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 
 import java.lang.reflect.Field;
@@ -284,19 +285,19 @@
      * The Component in an application that will typically receive all
      * KeyEvents generated by the user.
      */
-    private static Component focusOwner;
+    private static Reference<Component> focusOwner = new WeakReference<>(null);
 
     /**
      * The Component in an application that will regain focus when an
      * outstanding temporary focus transfer has completed, or the focus owner,
      * if no outstanding temporary transfer exists.
      */
-    private static Component permanentFocusOwner;
+    private static Reference<Component> permanentFocusOwner = new WeakReference<>(null);;
 
     /**
      * The Window which is, or contains, the focus owner.
      */
-    private static Window focusedWindow;
+    private static Reference<Window> focusedWindow = new WeakReference<>(null);
 
     /**
      * Only a Frame or a Dialog can be the active Window. The native windowing
@@ -305,7 +306,7 @@
      * Window, or the first Frame or Dialog which is an owner of the focused
      * Window.
      */
-    private static Window activeWindow;
+    private static Reference<Window> activeWindow = new WeakReference<>(null);
 
     /**
      * The default FocusTraversalPolicy for all Windows that have no policy of
@@ -472,12 +473,13 @@
      */
     public Component getFocusOwner() {
         synchronized (KeyboardFocusManager.class) {
-            if (focusOwner == null) {
+            final Component owner = focusOwner.get();
+            if (owner == null) {
                 return null;
             }
 
-            return (focusOwner.appContext == AppContext.getAppContext())
-                ? focusOwner
+            return (owner.appContext == AppContext.getAppContext())
+                ? owner
                 : null;
         }
     }
@@ -503,8 +505,9 @@
      */
     protected Component getGlobalFocusOwner() throws SecurityException {
         synchronized (KeyboardFocusManager.class) {
+            Component owner = focusOwner.get();
             if (this == getCurrentKeyboardFocusManager()) {
-                return focusOwner;
+                return owner;
             } else {
                 if (focusLog.isLoggable(PlatformLogger.FINER)) {
                     focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager());
@@ -554,7 +557,7 @@
                     return;
                 }
 
-                KeyboardFocusManager.focusOwner = focusOwner;
+                KeyboardFocusManager.focusOwner = new WeakReference<>(focusOwner);
 
                 if (focusOwner != null &&
                     (getCurrentFocusCycleRoot() == null ||
@@ -638,13 +641,14 @@
      */
     public Component getPermanentFocusOwner() {
         synchronized (KeyboardFocusManager.class) {
-            if (permanentFocusOwner == null) {
+            Component permaOwner = permanentFocusOwner.get();
+            if (permaOwner == null) {
                 return null;
             }
 
-            return (permanentFocusOwner.appContext ==
+            return (permaOwner.appContext ==
                     AppContext.getAppContext())
-                ? permanentFocusOwner
+                ? permaOwner
                 : null;
         }
     }
@@ -672,8 +676,9 @@
         throws SecurityException
     {
         synchronized (KeyboardFocusManager.class) {
+            Component permaOwner = permanentFocusOwner.get();
             if (this == getCurrentKeyboardFocusManager()) {
-                return permanentFocusOwner;
+                return permaOwner;
             } else {
                 if (focusLog.isLoggable(PlatformLogger.FINER)) {
                     focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager());
@@ -726,7 +731,7 @@
                     return;
                 }
 
-                KeyboardFocusManager.permanentFocusOwner = permanentFocusOwner;
+                KeyboardFocusManager.permanentFocusOwner = new WeakReference<>(permanentFocusOwner);
 
                 KeyboardFocusManager.
                     setMostRecentFocusOwner(permanentFocusOwner);
@@ -753,12 +758,13 @@
      */
     public Window getFocusedWindow() {
         synchronized (KeyboardFocusManager.class) {
-            if (focusedWindow == null) {
+            Window win = focusedWindow.get();
+            if (win == null) {
                 return null;
             }
 
-            return (focusedWindow.appContext == AppContext.getAppContext())
-                ? focusedWindow
+            return (win.appContext == AppContext.getAppContext())
+                ? win
                 : null;
         }
     }
@@ -780,8 +786,9 @@
      */
     protected Window getGlobalFocusedWindow() throws SecurityException {
         synchronized (KeyboardFocusManager.class) {
+            Window win = focusedWindow.get();
             if (this == getCurrentKeyboardFocusManager()) {
-               return focusedWindow;
+               return win;
             } else {
                 if (focusLog.isLoggable(PlatformLogger.FINER)) {
                     focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager());
@@ -828,7 +835,7 @@
                     return;
                 }
 
-                KeyboardFocusManager.focusedWindow = focusedWindow;
+                KeyboardFocusManager.focusedWindow = new WeakReference<>(focusedWindow);
                 shouldFire = true;
             }
         }
@@ -854,12 +861,13 @@
      */
     public Window getActiveWindow() {
         synchronized (KeyboardFocusManager.class) {
-            if (activeWindow == null) {
+            Window active = activeWindow.get();
+            if (active == null) {
                 return null;
             }
 
-            return (activeWindow.appContext == AppContext.getAppContext())
-                ? activeWindow
+            return (active.appContext == AppContext.getAppContext())
+                ? active
                 : null;
         }
     }
@@ -885,7 +893,7 @@
     protected Window getGlobalActiveWindow() throws SecurityException {
         synchronized (KeyboardFocusManager.class) {
             if (this == getCurrentKeyboardFocusManager()) {
-               return activeWindow;
+               return activeWindow.get();
             } else {
                 if (focusLog.isLoggable(PlatformLogger.FINER)) {
                     focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager());
@@ -933,7 +941,7 @@
                 return;
             }
 
-            KeyboardFocusManager.activeWindow = activeWindow;
+            KeyboardFocusManager.activeWindow = new WeakReference<>(activeWindow);
         }
 
         firePropertyChange("activeWindow", oldActiveWindow, activeWindow);

Reply via email to