如果我在性能环境中投入足够的流量,我可能会导致内存不足错误。如果我在此实例上执行线程转储,它将报告死锁:
Found one Java-level deadlock:
=============================
"http-nio-8080-exec-9":
waiting to lock monitor 0x00007fb528003098 (object 0x00000000826d6018, a com.mysql.jdbc.LoadBalancedConnectionProxy),
which is held by "Finalizer"
"Finalizer":
waiting to lock monitor 0x00007fb528002fe8 (object 0x00000000826d5f98, a com.mysql.jdbc.ReplicationConnectionProxy),
which is held by "http-nio-8080-exec-9"
我认为OOM正在发生,因为Finalizer已经死锁,无法收集未使用的实例。我不知道如何解决僵局问题。 http-nio-8080-exec-9线程正在这样做:
"http-nio-8080-exec-9":
at com.mysql.jdbc.MultiHostConnectionProxy$JdbcInterfaceProxy.invoke(MultiHostConnectionProxy.java:104)
- waiting to lock <0x00000000826d6018> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
at com.sun.proxy.$Proxy60.setPingTarget(Unknown Source)
at com.mysql.jdbc.ReplicationConnectionProxy.invokeMore(ReplicationConnectionProxy.java:311)
at com.mysql.jdbc.MultiHostConnectionProxy.invoke(MultiHostConnectionProxy.java:457)
- locked <0x00000000826d5f98> (a com.mysql.jdbc.ReplicationConnectionProxy)
at com.sun.proxy.$Proxy57.prepareStatement(Unknown Source)
at org.apache.commons.dbcp2.DelegatingConnection.prepareStatement(DelegatingConnection.java:291)
at org.apache.commons.dbcp2.DelegatingConnection.prepareStatement(DelegatingConnection.java:291)
my code here
在我的代码的这一行,我的代码是这样做的:
preparedStatement = connect.prepareStatement(sqlQuery);
终结者线程正在这样做:
"Finalizer":
at com.mysql.jdbc.ResultSetImpl.realClose(ResultSetImpl.java:6597)
- waiting to lock <0x00000000826d5f98> (a com.mysql.jdbc.ReplicationConnectionProxy)
at com.mysql.jdbc.ResultSetImpl.close(ResultSetImpl.java:851)
at sun.reflect.GeneratedMethodAccessor112.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.mysql.jdbc.MultiHostConnectionProxy$JdbcInterfaceProxy.invoke(MultiHostConnectionProxy.java:108)
- locked <0x00000000826d6018> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
at com.sun.proxy.$Proxy61.close(Unknown Source)
at sun.reflect.GeneratedMethodAccessor112.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.mysql.jdbc.MultiHostConnectionProxy$JdbcInterfaceProxy.invoke(MultiHostConnectionProxy.java:108)
- locked <0x00000000826d6018> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
at com.sun.proxy.$Proxy62.close(Unknown Source)
at org.apache.commons.dbcp2.DelegatingResultSet.close(DelegatingResultSet.java:169)
at org.apache.commons.dbcp2.DelegatingStatement.close(DelegatingStatement.java:149)
at org.apache.commons.dbcp2.DelegatingStatement.finalize(DelegatingStatement.java:549)
at java.lang.System$2.invokeFinalize(System.java:1270)
at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:98)
at java.lang.ref.Finalizer.access$100(Finalizer.java:34)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:210)
ResultSetImpl.realClose
在死锁时执行此操作:
synchronized (locallyScopedConn.getConnectionMutex()) {
两者似乎都与mysql jdbc驱动程序有关。我们正在使用org.apache.commons.dbcp2.BasicDataSource
来建立连接池。这是我们建立连接的代码:
private static final BasicDataSource dataSource = new BasicDataSource();
private void setUpConnectionPool()
{
final String JDBC_CONNECTION_STRING = System.getProperty("JDBC_CONNECTION_STRING");
final String DB_USER_STRING = System.getProperty("DB_USER_STRING");
final String DB_PASSWORD_STRING = System.getProperty("DB_PASSWORD_STRING");
final int MAX_CONNECTIONS = System.getProperty("MAX_CONNECTIONS") == null ? 100 : Integer.valueOf(System.getProperty("MAX_CONNECTIONS"));
try {
ReplicationDriver driver = new ReplicationDriver();
dataSource.setUrl(JDBC_CONNECTION_STRING);
dataSource.setDriver(driver);
dataSource.setUsername(DB_USER_STRING);
dataSource.setPassword(DB_PASSWORD_STRING);
dataSource.setMaxTotal(MAX_CONNECTIONS);
dataSource.setConnectionProperties("autoReconnect=true;roundRobinLoadBalance=true;");
} catch (Exception e) {
e.printStackTrace();
}
}
初始化上下文时调用上述方法。然后,所有代码都通过调用此方法获得其连接:
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
我希望这段代码有明显的错误,但是我没有看到它导致死锁的明显原因。