博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
聊聊GenericObjectPool的泄露检测
阅读量:5936 次
发布时间:2019-06-19

本文共 13129 字,大约阅读时间需要 43 分钟。

  hot3.png

本文主要聊聊GenericObjectPool的abandon参数。主要用来做连接池的泄露检测用。

object的状态

commons-pool2-2.4.2-sources.jar!/org/apache/commons/pool2/PooledObjectState.java

public enum PooledObjectState {    /**     * In the queue, not in use.     */    IDLE,    /**     * In use.     */    ALLOCATED,    /**     * In the queue, currently being tested for possible eviction.     */    EVICTION,    /**     * Not in the queue, currently being tested for possible eviction. An     * attempt to borrow the object was made while being tested which removed it     * from the queue. It should be returned to the head of the queue once     * eviction testing completes.     * TODO: Consider allocating object and ignoring the result of the eviction     *       test.     */    EVICTION_RETURN_TO_HEAD,    /**     * In the queue, currently being validated.     */    VALIDATION,    /**     * Not in queue, currently being validated. The object was borrowed while     * being validated and since testOnBorrow was configured, it was removed     * from the queue and pre-allocated. It should be allocated once validation     * completes.     */    VALIDATION_PREALLOCATED,    /**     * Not in queue, currently being validated. An attempt to borrow the object     * was made while previously being tested for eviction which removed it from     * the queue. It should be returned to the head of the queue once validation     * completes.     */    VALIDATION_RETURN_TO_HEAD,    /**     * Failed maintenance (e.g. eviction test or validation) and will be / has     * been destroyed     */    INVALID,    /**     * Deemed abandoned, to be invalidated.     */    ABANDONED,    /**     * Returning to the pool.     */    RETURNING}

abandon一般是用于连接泄露的检测,检测的是在使用的对象,比如怀疑那个对象被占用时间超长,那估计是程序异常或bug导致对象borrow了但忘记归还,或者对象borrow之后使用时间太长。

AbandonedConfig

除了commons-pool2-2.4.2-sources.jar!/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java,还有这个AbandonedConfig commons-pool2-2.4.2-sources.jar!/org/apache/commons/pool2/impl/AbandonedConfig.java

public class AbandonedConfig {    /**     * Whether or not borrowObject performs abandoned object removal.     */    private boolean removeAbandonedOnBorrow = false;    /**     * 

Flag to remove abandoned objects if they exceed the * removeAbandonedTimeout when borrowObject is invoked.

* *

The default value is false.

* *

If set to true, abandoned objects are removed by borrowObject if * there are fewer than 2 idle objects available in the pool and * getNumActive() > getMaxTotal() - 3

* * @return true if abandoned objects are to be removed by borrowObject */ public boolean getRemoveAbandonedOnBorrow() { return this.removeAbandonedOnBorrow; } /** *

Flag to remove abandoned objects if they exceed the * removeAbandonedTimeout when borrowObject is invoked.

* * @param removeAbandonedOnBorrow true means abandoned objects will be * removed by borrowObject * @see #getRemoveAbandonedOnBorrow() */ public void setRemoveAbandonedOnBorrow(boolean removeAbandonedOnBorrow) { this.removeAbandonedOnBorrow = removeAbandonedOnBorrow; } /** * Whether or not pool maintenance (evictor) performs abandoned object * removal. */ private boolean removeAbandonedOnMaintenance = false; /** * Timeout in seconds before an abandoned object can be removed. */ private int removeAbandonedTimeout = 300; /** * Determines whether or not to log stack traces for application code * which abandoned an object. */ private boolean logAbandoned = false; /** * PrintWriter to use to log information on abandoned objects. * Use of default system encoding is deliberate. */ private PrintWriter logWriter = new PrintWriter(System.out); /** * If the pool implements {@link UsageTracking}, should the pool record a * stack trace every time a method is called on a pooled object and retain * the most recent stack trace to aid debugging of abandoned objects? */ private boolean useUsageTracking = false;}

参数

  • removeAbandonedOnBorrow 在borrow的时候,是否执行abandon判断,默认false
  • removeAbandonedOnMaintenance 是否在evictor中执行abandon判断,默认false
  • removeAbandonedTimeout 一个对象在被borrow之后多少秒未归还则认为是abandon,默认为300
  • logAbandoned 是否打印abandon的日志,默认为false
  • useUsageTracking 是否追踪对象调用并保留最近的调用记录方便debug

removeAbandonedOnBorrow

在borrow方法里头

public T borrowObject(long borrowMaxWaitMillis) throws Exception {        assertOpen();        AbandonedConfig ac = this.abandonedConfig;        if (ac != null && ac.getRemoveAbandonedOnBorrow() &&                (getNumIdle() < 2) &&                (getNumActive() > getMaxTotal() - 3) ) {            removeAbandoned(ac);        }        PooledObject
p = null; // Get local copy of current config so it is consistent for entire // method execution boolean blockWhenExhausted = getBlockWhenExhausted(); boolean create; long waitTime = System.currentTimeMillis(); //...... updateStatsBorrow(p, System.currentTimeMillis() - waitTime); return p.getObject(); }

removeAbandonedOnMaintenance

在evictor线程里头

public void evict() throws Exception {        assertOpen();        if (idleObjects.size() > 0) {            PooledObject
underTest = null; EvictionPolicy
evictionPolicy = getEvictionPolicy(); synchronized (evictionLock) { EvictionConfig evictionConfig = new EvictionConfig( getMinEvictableIdleTimeMillis(), getSoftMinEvictableIdleTimeMillis(), getMinIdle()); boolean testWhileIdle = getTestWhileIdle(); for (int i = 0, m = getNumTests(); i < m; i++) { if (evictionIterator == null || !evictionIterator.hasNext()) { evictionIterator = new EvictionIterator(idleObjects); } if (!evictionIterator.hasNext()) { // Pool exhausted, nothing to do here return; } try { underTest = evictionIterator.next(); } catch (NoSuchElementException nsee) { // Object was borrowed in another thread // Don't count this as an eviction test so reduce i; i--; evictionIterator = null; continue; } if (!underTest.startEvictionTest()) { // Object was borrowed in another thread // Don't count this as an eviction test so reduce i; i--; continue; } // User provided eviction policy could throw all sorts of // crazy exceptions. Protect against such an exception // killing the eviction thread. boolean evict; try { evict = evictionPolicy.evict(evictionConfig, underTest, idleObjects.size()); } catch (Throwable t) { // Slightly convoluted as SwallowedExceptionListener // uses Exception rather than Throwable PoolUtils.checkRethrow(t); swallowException(new Exception(t)); // Don't evict on error conditions evict = false; } if (evict) { destroy(underTest); destroyedByEvictorCount.incrementAndGet(); } else { if (testWhileIdle) { boolean active = false; try { factory.activateObject(underTest); active = true; } catch (Exception e) { destroy(underTest); destroyedByEvictorCount.incrementAndGet(); } if (active) { if (!factory.validateObject(underTest)) { destroy(underTest); destroyedByEvictorCount.incrementAndGet(); } else { try { factory.passivateObject(underTest); } catch (Exception e) { destroy(underTest); destroyedByEvictorCount.incrementAndGet(); } } } } if (!underTest.endEvictionTest(idleObjects)) { // TODO - May need to add code here once additional // states are used } } } } } AbandonedConfig ac = this.abandonedConfig; if (ac != null && ac.getRemoveAbandonedOnMaintenance()) { removeAbandoned(ac); } }

removeAbandonedTimeout

在removeAbandoned方法里头

/**     * Recover abandoned objects which have been checked out but     * not used since longer than the removeAbandonedTimeout.     *     * @param ac The configuration to use to identify abandoned objects     */    private void removeAbandoned(AbandonedConfig ac) {        // Generate a list of abandoned objects to remove        final long now = System.currentTimeMillis();        final long timeout =                now - (ac.getRemoveAbandonedTimeout() * 1000L);        ArrayList
> remove = new ArrayList
>(); Iterator
> it = allObjects.values().iterator(); while (it.hasNext()) { PooledObject
pooledObject = it.next(); synchronized (pooledObject) { if (pooledObject.getState() == PooledObjectState.ALLOCATED && pooledObject.getLastUsedTime() <= timeout) { pooledObject.markAbandoned(); remove.add(pooledObject); } } } // Now remove the abandoned objects Iterator
> itr = remove.iterator(); while (itr.hasNext()) { PooledObject
pooledObject = itr.next(); if (ac.getLogAbandoned()) { pooledObject.printStackTrace(ac.getLogWriter()); } try { invalidateObject(pooledObject.getObject()); } catch (Exception e) { e.printStackTrace(); } } }

标记为abandon之后,立马放入remove队列中,然后遍历进行invalidateObject

public void invalidateObject(T obj) throws Exception {        PooledObject
p = allObjects.get(new IdentityWrapper
(obj)); if (p == null) { if (isAbandonedConfig()) { return; } else { throw new IllegalStateException( "Invalidated object not currently part of this pool"); } } synchronized (p) { if (p.getState() != PooledObjectState.INVALID) { destroy(p); } } ensureIdle(1, false); }

logAbandoned

最后是作用在这个类 commons-pool2-2.4.2-sources.jar!/org/apache/commons/pool2/impl/DefaultPooledObject.java

public synchronized boolean allocate() {        if (state == PooledObjectState.IDLE) {            state = PooledObjectState.ALLOCATED;            lastBorrowTime = System.currentTimeMillis();            lastUseTime = lastBorrowTime;            borrowedCount++;            if (logAbandoned) {                borrowedBy = new AbandonedObjectCreatedException();            }            return true;        } else if (state == PooledObjectState.EVICTION) {            // TODO Allocate anyway and ignore eviction test            state = PooledObjectState.EVICTION_RETURN_TO_HEAD;            return false;        }        // TODO if validating and testOnBorrow == true then pre-allocate for        // performance        return false;    }

useUsageTracking

public void use(T pooledObject) {        AbandonedConfig ac = this.abandonedConfig;        if (ac != null && ac.getUseUsageTracking()) {            PooledObject
wrapper = allObjects.get(new IdentityWrapper
(pooledObject)); wrapper.use(); } }

就是会调用一下PooledObject的use进行统计 commons-pool2-2.4.2-sources.jar!/org/apache/commons/pool2/proxy/BaseProxyHandler.java

/**     * Invoke the given method on the wrapped object.     *     * @param method    The method to invoke     * @param args      The arguments to the method     * @return          The result of the method call     * @throws Throwable    If the method invocation fails     */    Object doInvoke(Method method, Object[] args) throws Throwable {        validateProxiedObject();        T object = getPooledObject();        if (usageTracking != null) {            usageTracking.use(object);        }        return method.invoke(object, args);    }

doc

转载于:https://my.oschina.net/go4it/blog/1553544

你可能感兴趣的文章
「docker实战篇」python的docker爬虫技术-导学(一)
查看>>
linux日志基础介绍
查看>>
如何关闭SElinux
查看>>
处理器之MMU(三)
查看>>
172.16.82.0/25的含义,IP段,掩码
查看>>
测试之路
查看>>
终于对了
查看>>
RabbitMQ集群
查看>>
Apache防盗链和隐藏版本信息
查看>>
ARP协议与路由
查看>>
使用pypiserver搭建私有源
查看>>
SCI检索介绍
查看>>
Android开发之生成自己的签名文件及App签名打包
查看>>
如何提高阿里云上应用的可用性(二)
查看>>
云宏WinCloud前端工程师告诉你什么是UI扁平化
查看>>
如何压缩PDF文件,有什么简单的方法
查看>>
SpringMVC常用注解标签详解
查看>>
day18 Set集合
查看>>
Oracle event之db file read
查看>>
ORA 00600 [ktrexc_1]
查看>>