摘要:序本文主要聊聊的参数。主要用来做连接池的泄露检测用。的状态一般是用于连接泄露的检测,检测的是在使用的对象,比如怀疑那个对象被占用时间超长,那估计是程序异常或导致对象了但忘记归还,或者对象之后使用时间太长。
序
本文主要聊聊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
}
AbandonedConfigabandon一般是用于连接泄露的检测,检测的是在使用的对象,比如怀疑那个对象被占用时间超长,那估计是程序异常或bug导致对象borrow了但忘记归还,或者对象borrow之后使用时间太长。
除了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
在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
commons-pool2 2 - poolObject API与状态机
对象池common-pool2源码分析之对象状态
GenericObjectPool 避免泄漏
apache commons pool之GenericObjectPool分析(通用对象池技术)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/67838.html
摘要:如果为负值,表示不运行检测线程。默认为策略的类名,默认为这里就用到了上面提到的两个参数对象池原理分析避免泄漏配置参数详解,以及资源回收,从池中获取资源,将资源返还给池逻辑解析 序 本文主要解析一下apache common pools下的GenericObjectPool的参数设置 GenericObjectPool commons-pool2-2.4.2-sources.jar!/o...
摘要:实际应用中由于程序实现的问题,可能造成在一些极端的情况下出现没有被调用导致的泄漏问题。在的时候检查是否有泄漏的时候检查泄漏如果一个对象之后秒还没有返还给,认为是泄漏的对象秒运行一次维护任务 更多内容,请访问 https://my.oschina.net/u/5751... GenericObjectPool GenericObjectPool 是 Apache Commons Poo...
摘要:使用提供了中对象池管理方式,它们的使用方式基本一样,这里以对象池为例介绍其使用方式,一般实现自己的对象池需要经过个步骤实现接口该接口是一种工厂模式,实现其目的是让对象池通过该工厂模式创建管理的对象创建对象池实例创建对象池我们假设对象是一 common-pool2 使用 common-pool2提供了3中对象池管理方式,它们的使用方式基本一样,这里以GenericObjectPool对象...
阅读 3352·2021-11-25 09:43
阅读 1269·2021-11-24 10:22
阅读 1614·2021-09-22 15:26
阅读 962·2019-08-30 15:44
阅读 2733·2019-08-29 16:33
阅读 4093·2019-08-26 18:42
阅读 1101·2019-08-23 18:07
阅读 2066·2019-08-23 17:55