Skip to content

Commit 3973073

Browse files
committed
8253977: More memory leaks in client-libs on macOS
Reviewed-by: kizune
1 parent 2a0389a commit 3973073

File tree

5 files changed

+172
-49
lines changed

5 files changed

+172
-49
lines changed

src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -224,7 +224,7 @@ protected void uninstallListeners(final AbstractButton b) {
224224
b.removeAncestorListener(listener);
225225
}
226226
uninstallHierListener(b);
227-
AquaUtilControlSize.addSizePropertyListener(b);
227+
AquaUtilControlSize.removeSizePropertyListener(b);
228228
}
229229

230230
protected void uninstallDefaults(final AbstractButton b) {

src/java.desktop/macosx/classes/com/apple/laf/AquaSpinnerUI.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -141,7 +141,7 @@ public void uninstallUI(final JComponent c) {
141141
protected void installListeners() {
142142
spinner.addPropertyChangeListener(getPropertyChangeListener());
143143
JComponent editor = spinner.getEditor();
144-
if (editor != null && editor instanceof JSpinner.DefaultEditor) {
144+
if (editor instanceof DefaultEditor) {
145145
JTextField tf = ((JSpinner.DefaultEditor)editor).getTextField();
146146
if (tf != null) {
147147
tf.addFocusListener(getNextButtonHandler());
@@ -151,6 +151,14 @@ protected void installListeners() {
151151
}
152152

153153
protected void uninstallListeners() {
154+
JComponent editor = spinner.getEditor();
155+
if (editor instanceof DefaultEditor) {
156+
JTextField tf = ((JSpinner.DefaultEditor) editor).getTextField();
157+
if (tf != null) {
158+
tf.removeFocusListener(getNextButtonHandler());
159+
tf.removeFocusListener(getPreviousButtonHandler());
160+
}
161+
}
154162
spinner.removePropertyChangeListener(getPropertyChangeListener());
155163
}
156164

src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -491,12 +491,6 @@ public void updateIconImages() {
491491
getPlatformWindow().updateIconImages();
492492
}
493493

494-
@Override
495-
public void setBackground(final Color c) {
496-
super.setBackground(c);
497-
updateOpaque();
498-
}
499-
500494
@Override
501495
public void setOpacity(float opacity) {
502496
getPlatformWindow().setOpacity(opacity);

test/jdk/javax/swing/JFileChooser/FileChooserListenerLeak.java

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,14 @@
2121
* questions.
2222
*/
2323

24+
import java.awt.Component;
25+
import java.awt.Container;
2426
import java.awt.EventQueue;
2527

28+
import javax.swing.JComponent;
2629
import javax.swing.JFileChooser;
30+
import javax.swing.JMenu;
31+
import javax.swing.JMenuItem;
2732
import javax.swing.SwingUtilities;
2833
import javax.swing.UIManager;
2934
import javax.swing.UIManager.LookAndFeelInfo;
@@ -52,19 +57,33 @@ public static void main(final String[] args) throws Exception {
5257
});
5358
}
5459

55-
private static void checkListenersCount(JFileChooser chooser) {
56-
test(chooser.getComponentListeners());
57-
test(chooser.getFocusListeners());
58-
test(chooser.getHierarchyListeners());
59-
test(chooser.getHierarchyBoundsListeners());
60-
test(chooser.getKeyListeners());
61-
test(chooser.getMouseListeners());
62-
test(chooser.getMouseMotionListeners());
63-
test(chooser.getMouseWheelListeners());
64-
test(chooser.getInputMethodListeners());
65-
test(chooser.getPropertyChangeListeners());
66-
test(chooser.getAncestorListeners());
67-
test(chooser.getVetoableChangeListeners());
60+
private static void checkListenersCount(Component comp) {
61+
test(comp.getComponentListeners());
62+
test(comp.getFocusListeners());
63+
test(comp.getHierarchyListeners());
64+
test(comp.getHierarchyBoundsListeners());
65+
test(comp.getKeyListeners());
66+
test(comp.getMouseListeners());
67+
test(comp.getMouseMotionListeners());
68+
test(comp.getMouseWheelListeners());
69+
test(comp.getInputMethodListeners());
70+
test(comp.getPropertyChangeListeners());
71+
if (comp instanceof JComponent) {
72+
test(((JComponent) comp).getAncestorListeners());
73+
test(((JComponent) comp).getVetoableChangeListeners());
74+
}
75+
if (comp instanceof JMenuItem) {
76+
test(((JMenuItem) comp).getMenuKeyListeners());
77+
test(((JMenuItem) comp).getMenuDragMouseListeners());
78+
}
79+
if (comp instanceof JMenu) {
80+
test(((JMenu) comp).getMenuListeners());
81+
}
82+
if (comp instanceof Container) {
83+
for (Component child : ((Container) comp).getComponents()) {
84+
checkListenersCount(child);
85+
}
86+
}
6887
}
6988

7089
/**
@@ -73,7 +92,7 @@ private static void checkListenersCount(JFileChooser chooser) {
7392
*/
7493
private static void test(Object[] listeners) {
7594
int length = listeners.length;
76-
if (length > 10) {
95+
if (length > 20) {
7796
throw new RuntimeException("The count of listeners is: " + length);
7897
}
7998
}

test/jdk/javax/swing/UI/UnninstallUIMemoryLeaks/UnninstallUIMemoryLeaks.java

Lines changed: 126 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -21,47 +21,111 @@
2121
* questions.
2222
*/
2323

24+
import java.awt.Component;
25+
import java.awt.Container;
2426
import java.awt.EventQueue;
2527
import java.awt.FlowLayout;
28+
import java.util.ArrayList;
29+
import java.util.List;
30+
import java.util.concurrent.TimeUnit;
2631

27-
import javax.swing.*;
32+
import javax.swing.JButton;
33+
import javax.swing.JCheckBox;
34+
import javax.swing.JCheckBoxMenuItem;
35+
import javax.swing.JComboBox;
36+
import javax.swing.JComponent;
37+
import javax.swing.JDesktopPane;
38+
import javax.swing.JEditorPane;
39+
import javax.swing.JFormattedTextField;
40+
import javax.swing.JFrame;
41+
import javax.swing.JInternalFrame;
42+
import javax.swing.JLabel;
43+
import javax.swing.JList;
44+
import javax.swing.JMenu;
45+
import javax.swing.JMenuBar;
46+
import javax.swing.JMenuItem;
47+
import javax.swing.JPanel;
48+
import javax.swing.JPasswordField;
49+
import javax.swing.JProgressBar;
50+
import javax.swing.JRadioButton;
51+
import javax.swing.JRadioButtonMenuItem;
52+
import javax.swing.JScrollBar;
53+
import javax.swing.JScrollPane;
54+
import javax.swing.JSeparator;
55+
import javax.swing.JSlider;
56+
import javax.swing.JSpinner;
57+
import javax.swing.JSplitPane;
58+
import javax.swing.JTabbedPane;
59+
import javax.swing.JTable;
60+
import javax.swing.JTextArea;
61+
import javax.swing.JTextField;
62+
import javax.swing.JTextPane;
63+
import javax.swing.JToggleButton;
64+
import javax.swing.JToolBar;
65+
import javax.swing.JToolTip;
66+
import javax.swing.JTree;
67+
import javax.swing.JViewport;
68+
import javax.swing.SwingUtilities;
2869
import javax.swing.UIManager.LookAndFeelInfo;
2970

71+
import jdk.test.lib.process.OutputAnalyzer;
72+
import jdk.test.lib.process.ProcessTools;
73+
3074
import static javax.swing.UIManager.getInstalledLookAndFeels;
3175

3276
/**
3377
* @test
3478
* @key headful
35-
* @bug 8134947
36-
* @author Sergey Bylokhov
37-
* @run main/timeout=300/othervm -Xmx12m -XX:+HeapDumpOnOutOfMemoryError UnninstallUIMemoryLeaks
79+
* @bug 8134947 8253977
80+
* @library /test/lib
81+
* @run main/timeout=450/othervm UnninstallUIMemoryLeaks
3882
*/
3983
public final class UnninstallUIMemoryLeaks {
4084

4185
private static JFrame frame;
4286

43-
public static void main(final String[] args) throws Exception {
44-
try {
45-
createGUI();
46-
for (final LookAndFeelInfo laf : getInstalledLookAndFeels()) {
47-
final String name = laf.getName();
87+
public static void main(String[] args) throws Exception {
88+
if (args.length == 0) {
89+
long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(400);
90+
// run one task per look and feel
91+
List<Process> tasks = new ArrayList<>();
92+
for (LookAndFeelInfo laf : getInstalledLookAndFeels()) {
93+
String name = laf.getName();
4894
if (name.contains("OS X") || name.contains("Metal")) {
49-
SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf));
50-
SwingUtilities.invokeAndWait(() -> {
51-
for (int i = 0; i < 4000; ++i) {
52-
SwingUtilities.updateComponentTreeUI(frame);
53-
}
54-
});
95+
tasks.add(runProcess(laf));
5596
}
5697
}
98+
for (Process p : tasks) {
99+
if (!p.waitFor(end - System.nanoTime(), TimeUnit.NANOSECONDS)) {
100+
p.destroyForcibly();
101+
}
102+
}
103+
for (Process task : tasks) {
104+
new OutputAnalyzer(task).shouldHaveExitValue(0)
105+
.stderrShouldBeEmpty();
106+
}
107+
return;
108+
}
109+
110+
try {
111+
createGUI();
112+
long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(350);
113+
SwingUtilities.invokeAndWait(() -> {
114+
while (end > System.nanoTime()) {
115+
SwingUtilities.updateComponentTreeUI(frame);
116+
}
117+
checkListenersCount(frame);
118+
});
57119
} finally {
58-
if (frame != null) { EventQueue.invokeAndWait(() -> frame.dispose()); }
120+
if (frame != null) {EventQueue.invokeAndWait(frame::dispose);}
59121
}
60122
}
61123

62124
private static void createGUI() throws Exception {
63125
EventQueue.invokeAndWait(() -> {
64126
frame = new JFrame();
127+
//TODO we sometimes generate unnecessary repaint events
128+
frame.setIgnoreRepaint(true);
65129
frame.setLayout(new FlowLayout());
66130

67131
frame.add(new JButton("JButton"));
@@ -121,13 +185,51 @@ private static void createGUI() throws Exception {
121185
});
122186
}
123187

124-
private static void setLookAndFeel(final LookAndFeelInfo laf) {
125-
try {
126-
UIManager.setLookAndFeel(laf.getClassName());
127-
System.out.println("LookAndFeel: " + laf.getClassName());
128-
} catch (ClassNotFoundException | InstantiationException |
129-
UnsupportedLookAndFeelException | IllegalAccessException e) {
130-
throw new RuntimeException(e);
188+
private static void checkListenersCount(Component comp) {
189+
test(comp.getComponentListeners());
190+
test(comp.getFocusListeners());
191+
test(comp.getHierarchyListeners());
192+
test(comp.getHierarchyBoundsListeners());
193+
test(comp.getKeyListeners());
194+
test(comp.getMouseListeners());
195+
test(comp.getMouseMotionListeners());
196+
test(comp.getMouseWheelListeners());
197+
test(comp.getInputMethodListeners());
198+
test(comp.getPropertyChangeListeners());
199+
if (comp instanceof JComponent) {
200+
test(((JComponent) comp).getAncestorListeners());
201+
test(((JComponent) comp).getVetoableChangeListeners());
202+
}
203+
if (comp instanceof JMenuItem) {
204+
test(((JMenuItem) comp).getMenuKeyListeners());
205+
test(((JMenuItem) comp).getMenuDragMouseListeners());
206+
}
207+
if (comp instanceof JMenu) {
208+
test(((JMenu) comp).getMenuListeners());
209+
}
210+
if(comp instanceof Container) {
211+
for(Component child: ((Container)comp).getComponents()){
212+
checkListenersCount(child);
213+
}
131214
}
132215
}
216+
217+
/**
218+
* Checks the count of specific listeners, assumes that the proper
219+
* implementation does not use more than 20 listeners.
220+
*/
221+
private static void test(Object[] listeners) {
222+
int length = listeners.length;
223+
if (length > 20) {
224+
throw new RuntimeException("The count of listeners is: " + length);
225+
}
226+
}
227+
228+
private static Process runProcess(LookAndFeelInfo laf) throws Exception {
229+
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
230+
"-Dswing.defaultlaf=" + laf.getClassName(), "-mx9m",
231+
"-XX:+HeapDumpOnOutOfMemoryError",
232+
UnninstallUIMemoryLeaks.class.getSimpleName(), "mark");
233+
return ProcessTools.startProcess(laf.getName(), pb);
234+
}
133235
}

0 commit comments

Comments
 (0)