Java线程泄露的分析与处理
来源:互联网 发布:投诉淘宝卖家有用吗 编辑:程序博客网 时间:2024/06/03 21:12
1. 生产环境的异常现象及初步分析
最近发现系统程序内存消耗越来越大,开始并没特别注意,就简单调了一下jvm参数。但直到前些天内存爆满,持续Full GC,这肯定出现了内存泄露。
原以为哪里出现了比较低级的错误,所以很直接想到先去看看程序是在跑哪段代码下载。jstack -l <pid>
以后,居然有上千个线程,而且都是属于RUNNING并WAIT的状态。
I/O dispatcher 125" #739 prio=5 os_prio=0 tid=0x0000000002394800 nid=0x1e2a runnable [0x00007f5c2125b000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:79) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) - locked <0x00000007273401d0> (a sun.nio.ch.Util$2) - locked <0x00000007273401c0> (a java.util.Collections$UnmodifiableSet) - locked <0x00000007273401e0> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:257) at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590) at java.lang.Thread.run(Thread.java:745) Locked ownable synchronizers: - None"pool-224-thread-1" #738 prio=5 os_prio=0 tid=0x00007f5c463f4000 nid=0x1e29 runnable [0x00007f5c2024b000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:79) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) - locked <0x0000000727340478> (a sun.nio.ch.Util$2) - locked <0x0000000727340468> (a java.util.Collections$UnmodifiableSet) - locked <0x0000000727340488> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:342) at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:191) at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1.run(CloseableHttpAsyncClientBase.java:64) at java.lang.Thread.run(Thread.java:745) Locked ownable synchronizers: - None
我以下的思考路径都未能解决(自己记录一下,看官可以跳过...)
查看线程的stack,看调用处是否有问题。这个一般都能解决问题,但是上面的异常线程栈确实没什么信息量,无法定位。
Google了一下有关大量这个线程停在epollwait的资料,发现这个现象和epoll nio的bug是一样的,还以为碰到了一个无法处理的高级问题。第一反应就是去HttpClient的官网查bug日志,结果还真发现了最近的升级有解决类似问题的,然后升级到最新版问题依旧。但是最后仔细想想,也确实不太可能,毕竟应用场景还是比较普通的。
jmap -histo <pid>
看了一下对象,结果发现存在InternalHttpAsyncClient数量和泄露的线程数量刚好相等,所以基本就确定是这个对象的创建和回收有问题。但是这是谁创建的?查了调用栈和异常对象的package,发现是HttpClient的,把本地所有相关调用都查了一遍,看起来写的也都是对的。
搬出jvirtualvm的性能分析工具,发现只能看到泄露现象,无法定位问题。
这下懵逼了,刚好忙其他事,就放了几天顺带考虑一下,还好泄露比较慢,问题处理不着急。。。
2. 线程泄露的分析方法
处理这个问题的关键:必须准确知道是什么泄露了线程!
在Google过程中突然受到启发,JDK中的工具是应该可以分析引用的。最后发现jhat - Java Heap Analysis Tool正是我要的。
最终解决方式下载:
jmap -F -dump:format=b,file=tomcat.bin <pid>
导出tomcat的内存jhat -J-Xmx4g <heap dump file>
分析Heap中的信息(注意:分析非常消耗CPU和内存,尽量在配置较好的机器上运行)查看相关对象的reference,OQL也可以用,但是网页版直接点链接也够用了。
3. 锁定原因并解决
从之前异常heap中发现存在的问题对象有如下这些:
$ cat histo | grep org.apache.http. | grep 1944 | less 197: 1944 217728 org.apache.http.impl.nio.conn.ManagedNHttpClientConnectionImpl 232: 1944 171072 org.apache.http.impl.nio.conn.CPool 233: 1944 171072 org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor 248: 1944 155520 org.apache.http.impl.nio.reactor.BaseIOReactor 249: 1944 155520 org.apache.http.impl.nio.reactor.IOSessionImpl 276: 1944 139968 org.apache.http.impl.nio.client.InternalHttpAsyncClient 277: 1944 139968 org.apache.http.impl.nio.conn.CPoolEntry 323: 1944 108864 org.apache.http.impl.nio.client.MainClientExec 363: 1944 93312 org.apache.http.impl.nio.codecs.DefaultHttpResponseParser 401: 1944 77760 org.apache.http.impl.nio.reactor.SessionInputBufferImpl 402: 1944 77760 org.apache.http.impl.nio.reactor.SessionOutputBufferImpl 403: 1944 77760 org.apache.http.nio.protocol.HttpAsyncRequestExecutor$State 442: 1944 62208 org.apache.http.impl.cookie.DefaultCookieSpecProvider 443: 1944 62208 org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager 444: 1944 62208 org.apache.http.nio.conn.ssl.SSLIOSessionStrategy 445: 1944 62208 org.apache.http.nio.pool.AbstractNIOConnPool$2 511: 1944 46656 [Lorg.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker; 512: 1944 46656 [Lorg.apache.http.impl.nio.reactor.BaseIOReactor; 513: 1944 46656 org.apache.http.conn.ssl.DefaultHostnameVerifier 514: 1944 46656 org.apache.http.impl.cookie.DefaultCookieSpec 515: 1944 46656 org.apache.http.impl.cookie.NetscapeDraftSpecProvider 516: 1944 46656 org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1 517: 1944 46656 org.apache.http.impl.nio.client.InternalIODispatch 518: 1944 46656 org.apache.http.impl.nio.codecs.DefaultHttpRequestWriter 519: 1944 46656 org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager$ConfigData 520: 1944 46656 org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager$InternalAddressResolver 521: 1944 46656 org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager$InternalConnectionFactory 522: 1944 46656 org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker 523: 1944 46656 org.apache.http.nio.protocol.HttpAsyncRequestExecutor 603: 1944 31104 org.apache.http.client.protocol.RequestExpectContinue 604: 1944 31104 org.apache.http.conn.routing.BasicRouteDirector 605: 1944 31104 org.apache.http.impl.auth.HttpAuthenticator 606: 1944 31104 org.apache.http.impl.conn.DefaultRoutePlanner 607: 1944 31104 org.apache.http.impl.cookie.IgnoreSpecProvider 608: 1944 31104 org.apache.http.impl.nio.SessionHttpContext 609: 1944 31104 org.apache.http.impl.nio.reactor.AbstractIOReactor$1 610: 1944 31104 org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$DefaultThreadFactory 611: 1944 31104 org.apache.http.nio.pool.AbstractNIOConnPool$InternalSessionRequestCallback
接下来要找出到底谁new了这些对象,这些异常Object中很多是内部field,所以要先找出最外层的对象。这个就只是边猜边看了,结果发现就是InternalHttpAsyncClient。点开进去看了一下,发现有一堆Instance,最后了发现泄露的对象。也可以用OQL select referrers(c) from org.apache.http.impl.nio.client.InternalHttpAsyncClient c
instance of org.apache.http.impl.nio.client.InternalHttpAsyncClient@0x932be638 (128 bytes)Class:class org.apache.http.impl.nio.client.InternalHttpAsyncClientInstance data members:...References to this object:org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1@0x932be6c8 (40 bytes) : field this$0com.aliyun.mqs.common.http.DefaultServiceClient@0x931cc588 (32 bytes) : field httpClient
- Java线程泄露的分析与处理
- Java线程泄露的分析与处理
- Java线程泄露的分析与处理
- Java线程泄露的分析与处理
- java处理内存泄露与内存溢出的学习总结
- 处理线程泄露
- 处理线程泄露
- Java内存泄露分析, WeakReference与SoftReference
- Java常见问题分析(内存溢出、内存泄露、线程阻塞等)
- Java常见问题分析(内存溢出、内存泄露、线程阻塞等)
- Java常见问题分析(内存溢出、内存泄露、线程阻塞等)
- Java常见问题分析(内存溢出、内存泄露、线程阻塞等)
- Java常见问题分析(内存溢出、内存泄露、线程阻塞等)
- Android内存泄露原因分析与处理方案
- Handler内存泄露的分析与解决
- JAVA内存泄露的原因分析
- 关于java处理内存泄露与内存溢出的学习总结
- 内存泄露与分析
- Android JNI学习系列1.2—— JNI方法名,数据类型和方法签名的一些认识
- 将一个整型数组里面的元素转换成字符串类型
- chrome浏览器打开百度http出现warning或者红叉
- java ftpClient文件夹上传并在服务器按原分级显示
- 第13周项目3 Dijkstra算法的验证
- Java线程泄露的分析与处理
- 用VBA完成报表制作
- SVN客户端TortoiseSVN一次Add一个包含的多个文件夹和多个文件的文件夹添加不上的解决办法
- 安卓 重复创建界面
- 如何知道一个App的包名呢
- HTMLayout:制作无边框带阴影的窗口
- 如何设置PostgreSQL远程访问
- idea maven工程打可运行jar包方式
- MySQL Cluster 7.3.7+CentOS7集群配置入门 MySQL双管理节点配置入门