# HG changeset patch # User pchelko # Date 1360769249 0 # Node ID 014faa554d7abd7d1173a7c008fc4f2ccbe75548 # Parent 2c226ebab6a602ede0d3c660c488f6b9e8c07a4d 7079260: InputContext leaks memory Summary: Replaced strong refs with weak refs Reviewed-by: art, serb diff -r 2c226ebab6a6 -r 014faa554d7a jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java --- a/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java Wed Feb 13 19:23:09 2013 +0400 +++ b/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java Wed Feb 13 15:27:29 2013 +0000 @@ -33,6 +33,7 @@ import java.awt.font.TextAttribute; import java.awt.font.TextHitInfo; import java.awt.im.InputMethodRequests; +import java.lang.ref.WeakReference; import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator.Attribute; import java.text.AttributedString; @@ -55,7 +56,7 @@ private AttributedCharacterIterator composedText; private TextHitInfo caret = null; - private Component clientComponent = null; + private WeakReference clientComponent = new WeakReference<>(null); private InputMethodContext inputMethodContext; /** @@ -76,8 +77,9 @@ } // If the client component is an active client using below-the-spot style, then // make the composition window undecorated without a title bar. - if(clientComponent!=null){ - InputMethodRequests req = clientComponent.getInputMethodRequests(); + Component client = clientComponent.get(); + if(client != null){ + InputMethodRequests req = client.getInputMethodRequests(); if (req != null && inputMethodContext.useBelowTheSpotInput()) { setCompositionAreaUndecorated(true); } @@ -86,7 +88,7 @@ } void setClientComponent(Component clientComponent) { - this.clientComponent = clientComponent; + this.clientComponent = new WeakReference<>(clientComponent); } /** @@ -256,8 +258,9 @@ * the composed text are forwarded to the client component. */ InputMethodRequests getClientInputMethodRequests() { - if (clientComponent != null) { - return clientComponent.getInputMethodRequests(); + Component client = clientComponent.get(); + if (client != null) { + return client.getInputMethodRequests(); } return null; diff -r 2c226ebab6a6 -r 014faa554d7a jdk/src/solaris/classes/sun/awt/X11InputMethod.java --- a/jdk/src/solaris/classes/sun/awt/X11InputMethod.java Wed Feb 13 19:23:09 2013 +0400 +++ b/jdk/src/solaris/classes/sun/awt/X11InputMethod.java Wed Feb 13 15:27:29 2013 +0000 @@ -57,6 +57,7 @@ import java.io.FileReader; import java.io.BufferedReader; import java.io.IOException; +import java.lang.ref.WeakReference; import sun.util.logging.PlatformLogger; import java.util.StringTokenizer; import java.util.regex.Pattern; @@ -104,7 +105,7 @@ //reset the XIC if necessary private boolean needResetXIC = false; - private Component needResetXICClient = null; + private WeakReference needResetXICClient = new WeakReference<>(null); // The use of compositionEnableSupported is to reduce unnecessary // native calls if set/isCompositionEnabled @@ -272,14 +273,14 @@ called on the passive client when endComposition is called. */ if (needResetXIC && haveActiveClient() && - getClientComponent() != needResetXICClient){ + getClientComponent() != needResetXICClient.get()){ resetXIC(); // needs to reset the last xic focussed component. lastXICFocussedComponent = null; isLastXICActive = false; - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -417,7 +418,7 @@ isLastXICActive = false; resetXIC(); - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -478,7 +479,7 @@ disableInputMethod(); if (needResetXIC) { resetXIC(); - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -877,7 +878,7 @@ boolean active = haveActiveClient(); if (active && composedText == null && committedText == null){ needResetXIC = true; - needResetXICClient = getClientComponent(); + needResetXICClient = new WeakReference<>(getClientComponent()); return; } diff -r 2c226ebab6a6 -r 014faa554d7a jdk/test/java/awt/im/memoryleak/InputContextMemoryLeakTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/im/memoryleak/InputContextMemoryLeakTest.java Wed Feb 13 15:27:29 2013 +0000 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.FlowLayout; +import java.awt.Robot; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import test.java.awt.regtesthelpers.Util; + +/* + @test + @bug 7079260 + @summary XInputContext leaks memory by needRecetXXIClient field + @author Petr Pchelko + @library ../../regtesthelpers + @build Util + @compile InputContextMemoryLeakTest.java + @run main/othervm -Xmx20M InputContextMemoryLeakTest + */ +public class InputContextMemoryLeakTest { + + private static JFrame frame; + private static WeakReference text; + private static WeakReference p; + private static JButton button; + + public static void init() throws Throwable { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame(); + frame.setLayout(new FlowLayout()); + JPanel p1 = new JPanel(); + button = new JButton("Test"); + p1.add(button); + frame.add(p1); + text = new WeakReference(new JTextField("Text")); + p = new WeakReference(new JPanel(new FlowLayout())); + p.get().add(text.get()); + frame.add(p.get()); + frame.setBounds(500, 400, 200, 200); + frame.setVisible(true); + } + }); + + Util.focusComponent(text.get(), 500); + Util.clickOnComp(button, new Robot()); + //References to objects testes for memory leak are stored in Util. + //Need to clean them + Util.cleanUp(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.remove(p.get()); + } + }); + + Util.waitForIdle(null); + //After the next caret blink it automatically TextField references + Thread.sleep(text.get().getCaret().getBlinkRate() * 2); + Util.waitForIdle(null); + assertGC(); + } + + public static void assertGC() throws Throwable { + List alloc = new ArrayList(); + int size = 1024 * 10; + while (true) { + try { + alloc.add(new byte[size]); + } catch (OutOfMemoryError err) { + break; + } + } + alloc = null; + if (text.get() != null) { + throw new Exception("Test failed: JTextField was not collected"); + } + } + + public static void main(String args[]) throws Throwable { + init(); + } +} diff -r 2c226ebab6a6 -r 014faa554d7a jdk/test/java/awt/regtesthelpers/Util.java --- a/jdk/test/java/awt/regtesthelpers/Util.java Wed Feb 13 19:23:09 2013 +0400 +++ b/jdk/test/java/awt/regtesthelpers/Util.java Wed Feb 13 15:27:29 2013 +0000 @@ -463,6 +463,13 @@ return -1; } + //Cleans all the references + public static void cleanUp() { + apListener = null; + fgListener = null; + wgfListener = null; + } + //////////////////////////// // Some stuff to test focus.