摘要:序本文主要聊聊的參數(shù)。主要用來(lái)做連接池的泄露檢測(cè)用。的狀態(tài)一般是用于連接泄露的檢測(cè),檢測(cè)的是在使用的對(duì)象,比如懷疑那個(gè)對(duì)象被占用時(shí)間超長(zhǎng),那估計(jì)是程序異常或?qū)е聦?duì)象了但忘記歸還,或者對(duì)象之后使用時(shí)間太長(zhǎng)。
序
本文主要聊聊GenericObjectPool的abandon參數(shù)。主要用來(lái)做連接池的泄露檢測(cè)用。
object的狀態(tài)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 }
AbandonedConfigabandon一般是用于連接泄露的檢測(cè),檢測(cè)的是在使用的對(duì)象,比如懷疑那個(gè)對(duì)象被占用時(shí)間超長(zhǎng),那估計(jì)是程序異常或bug導(dǎo)致對(duì)象borrow了但忘記歸還,或者對(duì)象borrow之后使用時(shí)間太長(zhǎng)。
除了commons-pool2-2.4.2-sources.jar!/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java,還有這個(gè)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; /** *參數(shù)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 *
* * @return true if abandoned objects are to be removed by borrowObject */ public boolean getRemoveAbandonedOnBorrow() { return this.removeAbandonedOnBorrow; } /** *getNumActive() > getMaxTotal() - 3
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的時(shí)候,是否執(zhí)行abandon判斷,默認(rèn)false
removeAbandonedOnMaintenance
是否在evictor中執(zhí)行abandon判斷,默認(rèn)false
removeAbandonedTimeout
一個(gè)對(duì)象在被borrow之后多少秒未歸還則認(rèn)為是abandon,默認(rèn)為300
logAbandoned
是否打印abandon的日志,默認(rèn)為false
useUsageTracking
是否追蹤對(duì)象調(diào)用并保留最近的調(diào)用記錄方便debug
在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); } PooledObjectremoveAbandonedOnMaintenancep = 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(); }
在evictor線程里頭
public void evict() throws Exception { assertOpen(); if (idleObjects.size() > 0) { PooledObjectremoveAbandonedTimeoutunderTest = 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); } }
在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(); } } }
標(biāo)記為abandon之后,立馬放入remove隊(duì)列中,然后遍歷進(jìn)行invalidateObject
public void invalidateObject(T obj) throws Exception { PooledObjectlogAbandonedp = 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); }
最后是作用在這個(gè)類
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()) { PooledObjectwrapper = allObjects.get(new IdentityWrapper (pooledObject)); wrapper.use(); } }
就是會(huì)調(diào)用一下PooledObject的use進(jìn)行統(tǒng)計(jì)
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
commons-pool2 2 - poolObject API與狀態(tài)機(jī)
對(duì)象池common-pool2源碼分析之對(duì)象狀態(tài)
GenericObjectPool 避免泄漏
apache commons pool之GenericObjectPool分析(通用對(duì)象池技術(shù))
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/67838.html
摘要:如果為負(fù)值,表示不運(yùn)行檢測(cè)線程。默認(rèn)為策略的類名,默認(rèn)為這里就用到了上面提到的兩個(gè)參數(shù)對(duì)象池原理分析避免泄漏配置參數(shù)詳解,以及資源回收,從池中獲取資源,將資源返還給池邏輯解析 序 本文主要解析一下apache common pools下的GenericObjectPool的參數(shù)設(shè)置 GenericObjectPool commons-pool2-2.4.2-sources.jar!/o...
摘要:實(shí)際應(yīng)用中由于程序?qū)崿F(xiàn)的問題,可能造成在一些極端的情況下出現(xiàn)沒有被調(diào)用導(dǎo)致的泄漏問題。在的時(shí)候檢查是否有泄漏的時(shí)候檢查泄漏如果一個(gè)對(duì)象之后秒還沒有返還給,認(rèn)為是泄漏的對(duì)象秒運(yùn)行一次維護(hù)任務(wù) 更多內(nèi)容,請(qǐng)?jiān)L問 https://my.oschina.net/u/5751... GenericObjectPool GenericObjectPool 是 Apache Commons Poo...
摘要:使用提供了中對(duì)象池管理方式,它們的使用方式基本一樣,這里以對(duì)象池為例介紹其使用方式,一般實(shí)現(xiàn)自己的對(duì)象池需要經(jīng)過個(gè)步驟實(shí)現(xiàn)接口該接口是一種工廠模式,實(shí)現(xiàn)其目的是讓對(duì)象池通過該工廠模式創(chuàng)建管理的對(duì)象創(chuàng)建對(duì)象池實(shí)例創(chuàng)建對(duì)象池我們假設(shè)對(duì)象是一 common-pool2 使用 common-pool2提供了3中對(duì)象池管理方式,它們的使用方式基本一樣,這里以GenericObjectPool對(duì)象...
閱讀 3048·2021-11-25 09:43
閱讀 1027·2021-11-24 10:22
閱讀 1353·2021-09-22 15:26
閱讀 682·2019-08-30 15:44
閱讀 2463·2019-08-29 16:33
閱讀 3684·2019-08-26 18:42
閱讀 908·2019-08-23 18:07
閱讀 1832·2019-08-23 17:55