mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-14 00:49:42 +00:00
6566891: RMIConnector: map value referencing map key in WeakHashMap prevents map entry to be removed
Reviewed-by: egahlin, jbachorik, dfuchs, dholmes
This commit is contained in:
parent
cd65f6f973
commit
dbca0a2b85
@ -405,14 +405,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
throw new IOException("Not connected");
|
||||
}
|
||||
|
||||
MBeanServerConnection rmbsc = rmbscMap.get(delegationSubject);
|
||||
if (rmbsc != null) {
|
||||
return rmbsc;
|
||||
}
|
||||
|
||||
rmbsc = new RemoteMBeanServerConnection(delegationSubject);
|
||||
rmbscMap.put(delegationSubject, rmbsc);
|
||||
return rmbsc;
|
||||
return getConnectionWithSubject(delegationSubject);
|
||||
}
|
||||
|
||||
public void
|
||||
@ -1831,7 +1824,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
|
||||
// Initialization of transient variables.
|
||||
private void initTransients() {
|
||||
rmbscMap = new WeakHashMap<Subject, MBeanServerConnection>();
|
||||
rmbscMap = new WeakHashMap<Subject, WeakReference<MBeanServerConnection>>();
|
||||
connected = false;
|
||||
terminated = false;
|
||||
|
||||
@ -2011,6 +2004,25 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
private final ClassLoader loader;
|
||||
}
|
||||
|
||||
private MBeanServerConnection getConnectionWithSubject(Subject delegationSubject) {
|
||||
MBeanServerConnection conn = null;
|
||||
|
||||
if (delegationSubject == null) {
|
||||
if (nullSubjectConnRef == null
|
||||
|| (conn = nullSubjectConnRef.get()) == null) {
|
||||
conn = new RemoteMBeanServerConnection(null);
|
||||
nullSubjectConnRef = new WeakReference(conn);
|
||||
}
|
||||
} else {
|
||||
WeakReference<MBeanServerConnection> wr = rmbscMap.get(delegationSubject);
|
||||
if (wr == null || (conn = wr.get()) == null) {
|
||||
conn = new RemoteMBeanServerConnection(delegationSubject);
|
||||
rmbscMap.put(delegationSubject, new WeakReference(conn));
|
||||
}
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/*
|
||||
The following section of code avoids a class loading problem
|
||||
with RMI. The problem is that an RMI stub, when deserializing
|
||||
@ -2551,7 +2563,8 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
|
||||
private transient long clientNotifSeqNo = 0;
|
||||
|
||||
private transient WeakHashMap<Subject, MBeanServerConnection> rmbscMap;
|
||||
private transient WeakHashMap<Subject, WeakReference<MBeanServerConnection>> rmbscMap;
|
||||
private transient WeakReference<MBeanServerConnection> nullSubjectConnRef = null;
|
||||
|
||||
private transient RMINotifClient rmiNotifClient;
|
||||
// = new RMINotifClient(new Integer(0));
|
||||
|
||||
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.lang.management.ManagementFactory;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXConnectorServer;
|
||||
import javax.management.remote.JMXConnectorServerFactory;
|
||||
import javax.management.remote.JMXPrincipal;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.management.remote.rmi.RMIConnector;
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6566891
|
||||
* @summary Check no memory leak on RMIConnector's rmbscMap
|
||||
* @author Shanliang JIANG
|
||||
* @run clean RMIConnectorInternalMapTest
|
||||
* @run build RMIConnectorInternalMapTest
|
||||
* @run main RMIConnectorInternalMapTest
|
||||
*/
|
||||
|
||||
public class RMIConnectorInternalMapTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("---RMIConnectorInternalMapTest starting...");
|
||||
|
||||
JMXConnectorServer connectorServer = null;
|
||||
JMXConnector connectorClient = null;
|
||||
|
||||
try {
|
||||
MBeanServer mserver = ManagementFactory.getPlatformMBeanServer();
|
||||
JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0);
|
||||
connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver);
|
||||
connectorServer.start();
|
||||
|
||||
JMXServiceURL serverAddr = connectorServer.getAddress();
|
||||
connectorClient = JMXConnectorFactory.connect(serverAddr, null);
|
||||
connectorClient.connect();
|
||||
|
||||
Field rmbscMapField = RMIConnector.class.getDeclaredField("rmbscMap");
|
||||
rmbscMapField.setAccessible(true);
|
||||
Map<Subject, WeakReference<MBeanServerConnection>> map =
|
||||
(Map<Subject, WeakReference<MBeanServerConnection>>) rmbscMapField.get(connectorClient);
|
||||
if (map != null && !map.isEmpty()) { // failed
|
||||
throw new RuntimeException("RMIConnector's rmbscMap must be empty at the initial time.");
|
||||
}
|
||||
|
||||
Subject delegationSubject =
|
||||
new Subject(true,
|
||||
Collections.singleton(new JMXPrincipal("delegate")),
|
||||
Collections.EMPTY_SET,
|
||||
Collections.EMPTY_SET);
|
||||
MBeanServerConnection mbsc1 =
|
||||
connectorClient.getMBeanServerConnection(delegationSubject);
|
||||
MBeanServerConnection mbsc2 =
|
||||
connectorClient.getMBeanServerConnection(delegationSubject);
|
||||
|
||||
if (mbsc1 == null) {
|
||||
throw new RuntimeException("Got null connection.");
|
||||
}
|
||||
if (mbsc1 != mbsc2) {
|
||||
throw new RuntimeException("Not got same connection with a same subject.");
|
||||
}
|
||||
|
||||
map = (Map<Subject, WeakReference<MBeanServerConnection>>) rmbscMapField.get(connectorClient);
|
||||
if (map == null || map.isEmpty()) { // failed
|
||||
throw new RuntimeException("RMIConnector's rmbscMap has wrong size "
|
||||
+ "after creating a delegated connection.");
|
||||
}
|
||||
|
||||
delegationSubject = null;
|
||||
mbsc1 = null;
|
||||
mbsc2 = null;
|
||||
|
||||
int i = 0;
|
||||
while (!map.isEmpty() && i++ < 60) {
|
||||
System.gc();
|
||||
Thread.sleep(100);
|
||||
}
|
||||
System.out.println("---GC times: " + i);
|
||||
|
||||
if (!map.isEmpty()) {
|
||||
throw new RuntimeException("Failed to clean RMIConnector's rmbscMap");
|
||||
} else {
|
||||
System.out.println("---RMIConnectorInternalMapTest: PASSED!");
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
connectorClient.close();
|
||||
connectorServer.stop();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.lang.management.ManagementFactory;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXConnectorServer;
|
||||
import javax.management.remote.JMXConnectorServerFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.management.remote.rmi.RMIConnector;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6566891
|
||||
* @summary Check no memory leak on RMIConnector's nullSubjectConn
|
||||
* @author Shanliang JIANG
|
||||
* @run clean RMIConnectorNullSubjectConnTest
|
||||
* @run build RMIConnectorNullSubjectConnTest
|
||||
* @run main RMIConnectorNullSubjectConnTest
|
||||
*/
|
||||
|
||||
public class RMIConnectorNullSubjectConnTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("---RMIConnectorNullSubjectConnTest starting...");
|
||||
|
||||
JMXConnectorServer connectorServer = null;
|
||||
JMXConnector connectorClient = null;
|
||||
|
||||
try {
|
||||
MBeanServer mserver = ManagementFactory.getPlatformMBeanServer();
|
||||
JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0);
|
||||
connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver);
|
||||
connectorServer.start();
|
||||
|
||||
JMXServiceURL serverAddr = connectorServer.getAddress();
|
||||
connectorClient = JMXConnectorFactory.connect(serverAddr, null);
|
||||
connectorClient.connect();
|
||||
|
||||
Field nullSubjectConnField = RMIConnector.class.getDeclaredField("nullSubjectConnRef");
|
||||
nullSubjectConnField.setAccessible(true);
|
||||
|
||||
WeakReference<MBeanServerConnection> weak =
|
||||
(WeakReference<MBeanServerConnection>)nullSubjectConnField.get(connectorClient);
|
||||
|
||||
if (weak != null && weak.get() != null) {
|
||||
throw new RuntimeException("nullSubjectConnRef must be null at initial time.");
|
||||
}
|
||||
|
||||
MBeanServerConnection conn1 = connectorClient.getMBeanServerConnection(null);
|
||||
MBeanServerConnection conn2 = connectorClient.getMBeanServerConnection(null);
|
||||
if (conn1 == null) {
|
||||
throw new RuntimeException("A connection with null subject should not be null.");
|
||||
} else if (conn1 != conn2) {
|
||||
throw new RuntimeException("The 2 connections with null subject are not equal.");
|
||||
}
|
||||
|
||||
conn1 = null;
|
||||
conn2 = null;
|
||||
int i = 1;
|
||||
do {
|
||||
System.gc();
|
||||
Thread.sleep(100);
|
||||
weak = (WeakReference<MBeanServerConnection>)nullSubjectConnField.get(connectorClient);
|
||||
} while ((weak != null && weak.get() != null) && i++ < 60);
|
||||
|
||||
System.out.println("---GC times: " + i);
|
||||
|
||||
if (weak != null && weak.get() != null) {
|
||||
throw new RuntimeException("Failed to clean RMIConnector's nullSubjectConn");
|
||||
} else {
|
||||
System.out.println("---RMIConnectorNullSubjectConnTest: PASSED!");
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
connectorClient.close();
|
||||
connectorServer.stop();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user