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);