7079260: InputContext leaks memory
Replaced strong refs with weak refs Reviewed-by: art, serb
This commit is contained in:
parent
f44592861c
commit
42b8720bef
@ -33,6 +33,7 @@ import java.awt.event.InputMethodListener;
|
|||||||
import java.awt.font.TextAttribute;
|
import java.awt.font.TextAttribute;
|
||||||
import java.awt.font.TextHitInfo;
|
import java.awt.font.TextHitInfo;
|
||||||
import java.awt.im.InputMethodRequests;
|
import java.awt.im.InputMethodRequests;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.text.AttributedCharacterIterator;
|
import java.text.AttributedCharacterIterator;
|
||||||
import java.text.AttributedCharacterIterator.Attribute;
|
import java.text.AttributedCharacterIterator.Attribute;
|
||||||
import java.text.AttributedString;
|
import java.text.AttributedString;
|
||||||
@ -55,7 +56,7 @@ class CompositionAreaHandler implements InputMethodListener,
|
|||||||
|
|
||||||
private AttributedCharacterIterator composedText;
|
private AttributedCharacterIterator composedText;
|
||||||
private TextHitInfo caret = null;
|
private TextHitInfo caret = null;
|
||||||
private Component clientComponent = null;
|
private WeakReference<Component> clientComponent = new WeakReference<>(null);
|
||||||
private InputMethodContext inputMethodContext;
|
private InputMethodContext inputMethodContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,8 +77,9 @@ class CompositionAreaHandler implements InputMethodListener,
|
|||||||
}
|
}
|
||||||
// If the client component is an active client using below-the-spot style, then
|
// If the client component is an active client using below-the-spot style, then
|
||||||
// make the composition window undecorated without a title bar.
|
// make the composition window undecorated without a title bar.
|
||||||
if(clientComponent!=null){
|
Component client = clientComponent.get();
|
||||||
InputMethodRequests req = clientComponent.getInputMethodRequests();
|
if(client != null){
|
||||||
|
InputMethodRequests req = client.getInputMethodRequests();
|
||||||
if (req != null && inputMethodContext.useBelowTheSpotInput()) {
|
if (req != null && inputMethodContext.useBelowTheSpotInput()) {
|
||||||
setCompositionAreaUndecorated(true);
|
setCompositionAreaUndecorated(true);
|
||||||
}
|
}
|
||||||
@ -86,7 +88,7 @@ class CompositionAreaHandler implements InputMethodListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setClientComponent(Component clientComponent) {
|
void setClientComponent(Component clientComponent) {
|
||||||
this.clientComponent = clientComponent;
|
this.clientComponent = new WeakReference<>(clientComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,8 +258,9 @@ class CompositionAreaHandler implements InputMethodListener,
|
|||||||
* the composed text are forwarded to the client component.
|
* the composed text are forwarded to the client component.
|
||||||
*/
|
*/
|
||||||
InputMethodRequests getClientInputMethodRequests() {
|
InputMethodRequests getClientInputMethodRequests() {
|
||||||
if (clientComponent != null) {
|
Component client = clientComponent.get();
|
||||||
return clientComponent.getInputMethodRequests();
|
if (client != null) {
|
||||||
|
return client.getInputMethodRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -57,6 +57,7 @@ import java.io.File;
|
|||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import sun.util.logging.PlatformLogger;
|
import sun.util.logging.PlatformLogger;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -104,7 +105,7 @@ public abstract class X11InputMethod extends InputMethodAdapter {
|
|||||||
|
|
||||||
//reset the XIC if necessary
|
//reset the XIC if necessary
|
||||||
private boolean needResetXIC = false;
|
private boolean needResetXIC = false;
|
||||||
private Component needResetXICClient = null;
|
private WeakReference<Component> needResetXICClient = new WeakReference<>(null);
|
||||||
|
|
||||||
// The use of compositionEnableSupported is to reduce unnecessary
|
// The use of compositionEnableSupported is to reduce unnecessary
|
||||||
// native calls if set/isCompositionEnabled
|
// native calls if set/isCompositionEnabled
|
||||||
@ -272,14 +273,14 @@ public abstract class X11InputMethod extends InputMethodAdapter {
|
|||||||
called on the passive client when endComposition is called.
|
called on the passive client when endComposition is called.
|
||||||
*/
|
*/
|
||||||
if (needResetXIC && haveActiveClient() &&
|
if (needResetXIC && haveActiveClient() &&
|
||||||
getClientComponent() != needResetXICClient){
|
getClientComponent() != needResetXICClient.get()){
|
||||||
resetXIC();
|
resetXIC();
|
||||||
|
|
||||||
// needs to reset the last xic focussed component.
|
// needs to reset the last xic focussed component.
|
||||||
lastXICFocussedComponent = null;
|
lastXICFocussedComponent = null;
|
||||||
isLastXICActive = false;
|
isLastXICActive = false;
|
||||||
|
|
||||||
needResetXICClient = null;
|
needResetXICClient.clear();
|
||||||
needResetXIC = false;
|
needResetXIC = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,7 +418,7 @@ public abstract class X11InputMethod extends InputMethodAdapter {
|
|||||||
isLastXICActive = false;
|
isLastXICActive = false;
|
||||||
|
|
||||||
resetXIC();
|
resetXIC();
|
||||||
needResetXICClient = null;
|
needResetXICClient.clear();
|
||||||
needResetXIC = false;
|
needResetXIC = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -478,7 +479,7 @@ public abstract class X11InputMethod extends InputMethodAdapter {
|
|||||||
disableInputMethod();
|
disableInputMethod();
|
||||||
if (needResetXIC) {
|
if (needResetXIC) {
|
||||||
resetXIC();
|
resetXIC();
|
||||||
needResetXICClient = null;
|
needResetXICClient.clear();
|
||||||
needResetXIC = false;
|
needResetXIC = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -877,7 +878,7 @@ public abstract class X11InputMethod extends InputMethodAdapter {
|
|||||||
boolean active = haveActiveClient();
|
boolean active = haveActiveClient();
|
||||||
if (active && composedText == null && committedText == null){
|
if (active && composedText == null && committedText == null){
|
||||||
needResetXIC = true;
|
needResetXIC = true;
|
||||||
needResetXICClient = getClientComponent();
|
needResetXICClient = new WeakReference<>(getClientComponent());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
112
jdk/test/java/awt/im/memoryleak/InputContextMemoryLeakTest.java
Normal file
112
jdk/test/java/awt/im/memoryleak/InputContextMemoryLeakTest.java
Normal file
@ -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<JTextField> text;
|
||||||
|
private static WeakReference<JPanel> 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<JTextField>(new JTextField("Text"));
|
||||||
|
p = new WeakReference<JPanel>(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<byte[]> alloc = new ArrayList<byte[]>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
@ -463,6 +463,13 @@ public final class Util {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Cleans all the references
|
||||||
|
public static void cleanUp() {
|
||||||
|
apListener = null;
|
||||||
|
fgListener = null;
|
||||||
|
wgfListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
// Some stuff to test focus.
|
// Some stuff to test focus.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user