8253977: More memory leaks in client-libs on macOS

Reviewed-by: kizune
This commit is contained in:
Sergey Bylokhov 2020-10-07 03:06:35 +00:00
parent 2a0389a892
commit 397307311e
5 changed files with 172 additions and 49 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -224,7 +224,7 @@ public class AquaButtonUI extends BasicButtonUI implements Sizeable {
b.removeAncestorListener(listener); b.removeAncestorListener(listener);
} }
uninstallHierListener(b); uninstallHierListener(b);
AquaUtilControlSize.addSizePropertyListener(b); AquaUtilControlSize.removeSizePropertyListener(b);
} }
protected void uninstallDefaults(final AbstractButton b) { protected void uninstallDefaults(final AbstractButton b) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -141,7 +141,7 @@ public class AquaSpinnerUI extends SpinnerUI {
protected void installListeners() { protected void installListeners() {
spinner.addPropertyChangeListener(getPropertyChangeListener()); spinner.addPropertyChangeListener(getPropertyChangeListener());
JComponent editor = spinner.getEditor(); JComponent editor = spinner.getEditor();
if (editor != null && editor instanceof JSpinner.DefaultEditor) { if (editor instanceof DefaultEditor) {
JTextField tf = ((JSpinner.DefaultEditor)editor).getTextField(); JTextField tf = ((JSpinner.DefaultEditor)editor).getTextField();
if (tf != null) { if (tf != null) {
tf.addFocusListener(getNextButtonHandler()); tf.addFocusListener(getNextButtonHandler());
@ -151,6 +151,14 @@ public class AquaSpinnerUI extends SpinnerUI {
} }
protected void uninstallListeners() { protected void uninstallListeners() {
JComponent editor = spinner.getEditor();
if (editor instanceof DefaultEditor) {
JTextField tf = ((JSpinner.DefaultEditor) editor).getTextField();
if (tf != null) {
tf.removeFocusListener(getNextButtonHandler());
tf.removeFocusListener(getPreviousButtonHandler());
}
}
spinner.removePropertyChangeListener(getPropertyChangeListener()); spinner.removePropertyChangeListener(getPropertyChangeListener());
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -491,12 +491,6 @@ public class LWWindowPeer
getPlatformWindow().updateIconImages(); getPlatformWindow().updateIconImages();
} }
@Override
public void setBackground(final Color c) {
super.setBackground(c);
updateOpaque();
}
@Override @Override
public void setOpacity(float opacity) { public void setOpacity(float opacity) {
getPlatformWindow().setOpacity(opacity); getPlatformWindow().setOpacity(opacity);

View file

@ -21,9 +21,14 @@
* questions. * questions.
*/ */
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue; import java.awt.EventQueue;
import javax.swing.JComponent;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.UIManager.LookAndFeelInfo;
@ -52,19 +57,33 @@ public final class FileChooserListenerLeak {
}); });
} }
private static void checkListenersCount(JFileChooser chooser) { private static void checkListenersCount(Component comp) {
test(chooser.getComponentListeners()); test(comp.getComponentListeners());
test(chooser.getFocusListeners()); test(comp.getFocusListeners());
test(chooser.getHierarchyListeners()); test(comp.getHierarchyListeners());
test(chooser.getHierarchyBoundsListeners()); test(comp.getHierarchyBoundsListeners());
test(chooser.getKeyListeners()); test(comp.getKeyListeners());
test(chooser.getMouseListeners()); test(comp.getMouseListeners());
test(chooser.getMouseMotionListeners()); test(comp.getMouseMotionListeners());
test(chooser.getMouseWheelListeners()); test(comp.getMouseWheelListeners());
test(chooser.getInputMethodListeners()); test(comp.getInputMethodListeners());
test(chooser.getPropertyChangeListeners()); test(comp.getPropertyChangeListeners());
test(chooser.getAncestorListeners()); if (comp instanceof JComponent) {
test(chooser.getVetoableChangeListeners()); test(((JComponent) comp).getAncestorListeners());
test(((JComponent) comp).getVetoableChangeListeners());
}
if (comp instanceof JMenuItem) {
test(((JMenuItem) comp).getMenuKeyListeners());
test(((JMenuItem) comp).getMenuDragMouseListeners());
}
if (comp instanceof JMenu) {
test(((JMenu) comp).getMenuListeners());
}
if (comp instanceof Container) {
for (Component child : ((Container) comp).getComponents()) {
checkListenersCount(child);
}
}
} }
/** /**
@ -73,7 +92,7 @@ public final class FileChooserListenerLeak {
*/ */
private static void test(Object[] listeners) { private static void test(Object[] listeners) {
int length = listeners.length; int length = listeners.length;
if (length > 10) { if (length > 20) {
throw new RuntimeException("The count of listeners is: " + length); throw new RuntimeException("The count of listeners is: " + length);
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,47 +21,111 @@
* questions. * questions.
*/ */
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.FlowLayout; import java.awt.FlowLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.swing.*; import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JEditorPane;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.JRadioButton;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.JToolTip;
import javax.swing.JTree;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.UIManager.LookAndFeelInfo;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import static javax.swing.UIManager.getInstalledLookAndFeels; import static javax.swing.UIManager.getInstalledLookAndFeels;
/** /**
* @test * @test
* @key headful * @key headful
* @bug 8134947 * @bug 8134947 8253977
* @author Sergey Bylokhov * @library /test/lib
* @run main/timeout=300/othervm -Xmx12m -XX:+HeapDumpOnOutOfMemoryError UnninstallUIMemoryLeaks * @run main/timeout=450/othervm UnninstallUIMemoryLeaks
*/ */
public final class UnninstallUIMemoryLeaks { public final class UnninstallUIMemoryLeaks {
private static JFrame frame; private static JFrame frame;
public static void main(final String[] args) throws Exception { public static void main(String[] args) throws Exception {
if (args.length == 0) {
long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(400);
// run one task per look and feel
List<Process> tasks = new ArrayList<>();
for (LookAndFeelInfo laf : getInstalledLookAndFeels()) {
String name = laf.getName();
if (name.contains("OS X") || name.contains("Metal")) {
tasks.add(runProcess(laf));
}
}
for (Process p : tasks) {
if (!p.waitFor(end - System.nanoTime(), TimeUnit.NANOSECONDS)) {
p.destroyForcibly();
}
}
for (Process task : tasks) {
new OutputAnalyzer(task).shouldHaveExitValue(0)
.stderrShouldBeEmpty();
}
return;
}
try { try {
createGUI(); createGUI();
for (final LookAndFeelInfo laf : getInstalledLookAndFeels()) { long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(350);
final String name = laf.getName();
if (name.contains("OS X") || name.contains("Metal")) {
SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf));
SwingUtilities.invokeAndWait(() -> { SwingUtilities.invokeAndWait(() -> {
for (int i = 0; i < 4000; ++i) { while (end > System.nanoTime()) {
SwingUtilities.updateComponentTreeUI(frame); SwingUtilities.updateComponentTreeUI(frame);
} }
checkListenersCount(frame);
}); });
}
}
} finally { } finally {
if (frame != null) { EventQueue.invokeAndWait(() -> frame.dispose()); } if (frame != null) {EventQueue.invokeAndWait(frame::dispose);}
} }
} }
private static void createGUI() throws Exception { private static void createGUI() throws Exception {
EventQueue.invokeAndWait(() -> { EventQueue.invokeAndWait(() -> {
frame = new JFrame(); frame = new JFrame();
//TODO we sometimes generate unnecessary repaint events
frame.setIgnoreRepaint(true);
frame.setLayout(new FlowLayout()); frame.setLayout(new FlowLayout());
frame.add(new JButton("JButton")); frame.add(new JButton("JButton"));
@ -121,13 +185,51 @@ public final class UnninstallUIMemoryLeaks {
}); });
} }
private static void setLookAndFeel(final LookAndFeelInfo laf) { private static void checkListenersCount(Component comp) {
try { test(comp.getComponentListeners());
UIManager.setLookAndFeel(laf.getClassName()); test(comp.getFocusListeners());
System.out.println("LookAndFeel: " + laf.getClassName()); test(comp.getHierarchyListeners());
} catch (ClassNotFoundException | InstantiationException | test(comp.getHierarchyBoundsListeners());
UnsupportedLookAndFeelException | IllegalAccessException e) { test(comp.getKeyListeners());
throw new RuntimeException(e); test(comp.getMouseListeners());
test(comp.getMouseMotionListeners());
test(comp.getMouseWheelListeners());
test(comp.getInputMethodListeners());
test(comp.getPropertyChangeListeners());
if (comp instanceof JComponent) {
test(((JComponent) comp).getAncestorListeners());
test(((JComponent) comp).getVetoableChangeListeners());
}
if (comp instanceof JMenuItem) {
test(((JMenuItem) comp).getMenuKeyListeners());
test(((JMenuItem) comp).getMenuDragMouseListeners());
}
if (comp instanceof JMenu) {
test(((JMenu) comp).getMenuListeners());
}
if(comp instanceof Container) {
for(Component child: ((Container)comp).getComponents()){
checkListenersCount(child);
} }
} }
} }
/**
* Checks the count of specific listeners, assumes that the proper
* implementation does not use more than 20 listeners.
*/
private static void test(Object[] listeners) {
int length = listeners.length;
if (length > 20) {
throw new RuntimeException("The count of listeners is: " + length);
}
}
private static Process runProcess(LookAndFeelInfo laf) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-Dswing.defaultlaf=" + laf.getClassName(), "-mx9m",
"-XX:+HeapDumpOnOutOfMemoryError",
UnninstallUIMemoryLeaks.class.getSimpleName(), "mark");
return ProcessTools.startProcess(laf.getName(), pb);
}
}