压测调优之遇到的proxool问题
来源:互联网 发布:python全局变量的使用 编辑:程序博客网 时间:2024/04/29 13:15
T4CPreparedStatement内存泄露现象
现象
- 200并发压测压10分钟左右内存吃满
- jmap -histo | head 20 发现有大量的Connection对象和T4CPreparedStatement以及部分Finalizer对象,dump下来分析发现Connection和PreparedStatement这些对象都是no gc root
线程dump发现finalizer线程时常blocked在connection.isReallyClosed,而拿着锁的线程在执行数据库读写
"Finalizer" - Thread t@3 java.lang.Thread.State: BLOCKED at oracle.jdbc.driver.PhysicalConnection.isClosed(PhysicalConnection.java:1508) - waiting to lock <785dbebb> (a oracle.jdbc.driver.T4CConnection) owned by "http-bio-80-exec-19" t@70 at org.logicalcobwebs.proxool.ProxyConnection.isReallyClosed(ProxyConnection.java:206) at org.logicalcobwebs.proxool.WrappedConnection.invoke(WrappedConnection.java:114) at org.logicalcobwebs.proxool.WrappedConnection.intercept(WrappedConnection.java:87) at oracle.jdbc.internal.OracleConnection$$EnhancerByProxool$$9245683f.finalize(<generated>) at java.lang.System$2.invokeFinalize(System.java:1213) 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)
压测停后内存能释放掉
原因
在jvm回收WrappedConnection对象时,由于代理类重写了finalize方法,WrappedConnection方法被丢进引用队列等待finalizer线程执行finalize方法,finalize本身没有额外的实现,但是代理类在执行该方法之前会做一个isClose的判断,而jdbc oracle的实现类则使用了synchronize修饰了isClose,导致业务逻辑从池里拿出来该连接使用的时候会与finalize线程竞争该锁,一旦业务逻辑处于繁忙状态则finalizer线程执行的频率大大减小,此时在队列中的引用依然存在,对象仍然会在堆中存活。
分析
为啥会出现大量T4CPreparedStatement和WrappedConnection的对象在内存不被释放
从堆dump来看,T4CPreparedStatement占用最大的字节数,基本维持在1G以上,依据这个信息查看ibatis源码(其中我们这边在ibatis上层还封装了一个分库分表组件,而且是第一次使用,分库分表组件是当时重点查看的方向),发现T4CPreparedStatement这个对象生命周期只会在Ibatis的Executor这一层的doQuery和doUpdate这里,所以重点怀疑了数据库执行缓慢导致GC回收多次回收不掉从而被丢到老年代;通过打印耗时排除了这个想法。
之后突然发现这些对象都是no gc root,这样的话按照GC规则没道理不被释放吧?
为啥这些对象是no gc root还不被释放
之前完全没接触到no gc root不被释放是什么情况,然后还是碰巧地从线程堆栈中发现了Finalizer线程处于Blocked状态(调优目前都靠灵光一闪。。有好的调优方法的同学麻烦分享下),然后确定方向大致是要么是proxool或者是oracle实现Connection时做了锁操作或者更多的耗时操作,然后根据线程dump查看proxool的源码发现proxool的代理类每个方法(包括finalize)都会调用isReallyClosed会调用到oracle的加锁方法isClosed,然后也google相关信息发现已经有同学提供了补丁。
为啥会伴随这么多的Finalizer对象
每次GC完,JVM发现该对象实现了finalize方法,就会封装一个Finalizer对象,将待回收对象的引用丢给Finalizer对象,然后将Finalizer对象放到引用队列,Finalizer线程每次从该队列取出Finalizer对象执行引用的finalize方法。所以在上述情况基本每个finalize方法都很慢的情况下,会导致大量的Finalizer在引用队列,并且其中应用的待回收对象也在堆中无法释放。
参考
- http://www.majin163.com/2014/04/26/jvm-finalize/ (这个里面有句话是“它本身是个级别较低的线程”,它指的是Finalizer线程,这里要纠正下,Finalizer线程级别是Max-2也就是8,而线程默认值是5,所以这里跟线程优先级别是没太大关系的,主要还是执行太慢)
- http://blog.csdn.net/pdw2009/article/details/7864932#
- https://sourceforge.net/p/proxool/bugs/45/
创建代理对象blocked问题
现象
- 在解决完proxool导致的内存无法回收问题之后,再来压测,发现TPS和响应时间还是不理想,主要耗时还是集中在数据库操作从ibatis模块往下的部分,而且dump出来由很多如下blocked
- 在解决完proxool导致的内存无法回收问题之后,再来压测,发现TPS和响应时间还是不理想,主要耗时还是集中在数据库操作从ibatis模块往下的部分,而且dump出来由很多如下blocked
解决
- 线程dump大部分线程处于数据库操作,然后和DBA对比SQL执行耗时无阻塞SQL或耗时SQL
- 从ibatis模块往下使用aspectj weaver一段段代码切入查看耗时,发现从proxool层往下openSession、session.execute这两个操作都偶尔存在大量耗时
- 有了前面的经验,严重怀疑proxool的问题,从线程dump看出多半是proxool使用cglib创建代理对象时等锁,而且看实现基本每次preparedStatement都要创建一个,另外再回想起代理类里面的基本每个操作都执行下isRealyClose且带锁的操作,决定使用druid换掉proxool,TPS翻倍,耗时减半
参考
- https://github.com/alibaba/druid/wiki/%E5%90%84%E7%A7%8D%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0%E5%AF%B9%E6%AF%94
总结
不要使用proxool!
不要使用proxool!
不要使用proxool!
最起码oracle数据库就别用proxool了,已经无人维护状态,一开始看druid的官方文档说oracle的别用proxool一直以为他们是在自卖自夸,通过实践证明,确实不要用。
以下是druid的给出的说明。
PSCache是数据库连接池的关键指标。在Oracle中,类似SELECT NAME FROM USER WHERE ID = ?这样的SQL,启用PSCache和不启用PSCache的性能可能是相差一个数量级的。Proxool是不支持PSCache的数据库连接池,如果你使用Oracle、SQL Server、DB2、Sybase这样支持游标的数据库,那你就完全不用考虑Proxool。
- 压测调优之遇到的proxool问题
- Spring 中配置proxool连接池遇到的问题
- proxool与c3p0在使用中遇到的问题与解决办法
- proxool难搞的问题
- proxool连接池问题搞的头疼
- Proxool连接池的释放问题
- 容易遇到的问题之word07问题
- MFC遇到的问题 之 戊子年戌月壬卯日
- php之mail函数遇到的问题
- hadoop 之路我遇到的问题
- Android之ActionBar遇到的问题
- SparkR遇到的问题之找不到路径
- 前端之css遇到的问题
- Android之webview遇到的问题记录
- React-Native之路上遇到的问题
- 工作笔记之遇到的问题总结
- Proxool 版本bug问题
- Proxool连接池的释放问题(转)
- 使用jacob将word转为pdf时报com.jacob.com.ComFailException: Invoke of: SaveAs ...
- <LeetCode><Medium>17Letter Combinations of a Phone Number
- Tensorflow简单教程
- swift里采用cocoapods的方式集成高德地图遇到的问题
- POJ 2954 Triangle (皮克定理)
- 压测调优之遇到的proxool问题
- 【BZOJ3293】[Cqoi2011]分金币【绝对值不等式】【中位数】【数形结合】
- 大型广告系统架构概述
- java求学之路
- 《JAVA与模式》之装饰模式
- java中的内部类总结
- JavaScript编写人机对战五子棋(四)
- Java---设计模块(值对象)
- ListView的编写方法