mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-24 04:54:40 +02:00
8253977: More memory leaks in client-libs on macOS
Reviewed-by: kizune
This commit is contained in:
parent
2a0389a892
commit
397307311e
5 changed files with 172 additions and 49 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue