文
章
目
录
章
目
录
本文主要讲解关于如何排查解决大量创建连接池导致的线程泄漏问题相关内容,让我们来一起学习下吧!
对的, 你没看错, 大量创建连接池, 连接是稳定的, 但是却导致线程暴涨.
现象
这是一个Java 应用, 有监控它的线程总数, 各个服务器的线程总数看上去是这个样子的:
查看不断增长的线程
通过thread dump, 我们可以看到里面包含居多以 Connection evictor
命名的线程, 如下:
还碰巧看到一个正在做事的线程栈, 从这里我们可以大概猜出这是 Apache httpClient 的连接池, 它正在清理长期不用的连接.
我们推测这个应用在不断的创建连接池, 然后就抛弃不用, 然后就该 Connection evictor
出场来清理这些不再被使用的连接.
验证推断
既然推断创建了很多连接池, 那么我们就来看看到底有多少连接池.
$ jcmd 2447856 GC.class_histogram | grep PoolingHttpClientConnectionManager
223: 3211 101568 org.apache.http.impl.conn.PoolingHttpClientConnectionManager
224: 3211 101568 org.apache.http.impl.conn.PoolingHttpClientConnectionManager$ConfigData
284: 3211 86176 org.apache.http.impl.conn.PoolingHttpClientConnectionManager$InternalConnectionFactory
上面第二列的输出表示有多少这样的对象, 不出所料, 果然有这么多连接池.
找出真凶, 哪里创建这么多连接池
既然创建这么多 PoolingHttpClientConnectionManager
对象, 那么就看看到底哪里新建的这些对象吧. 使用 Btrace 工具, 使用如下Btrace 脚本:
import org.openjdk.btrace.core.annotations.*;
import static org.openjdk.btrace.core.BTraceUtils.*;
import org.openjdk.btrace.core.BTraceUtils.Strings;
@BTrace
public class ConnectionPoolTracer {
@OnMethod( clazz="/org\.apache\.http\.impl\.conn\.PoolingHttpClientConnectionManager/", method="<init>" )
public static void createPool() {
println(Strings.strcat("current thread: ", name(currentThread())));
println(jstackStr());
}
}
去执行, 得到如下栈:
org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:165)
org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:988)
org.tianxiaohui.utils.HttpConnectionUtils.getHttpConnection(HttpConnectionUtils.java:56)
org.tianxiaohui.utils.HttpUtils.createClientWithSSL(HttpUtils.java:144)
org.tianxiaohui.utils.HttpUtils.createClientWithSSL(HttpUtils.java:128)
org.tianxiaohui.service.CustomProperties.getVariable(CustomProperties.java:1133)
原来是每次调用 HttpConnectionUtils.getHttpConnection()
这个方法, 就会创建一个新的连接池.
修复
全局共享的一个连接池.
以上就是关于如何排查解决大量创建连接池导致的线程泄漏问题相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!