[#4147] Allow to disable recycling

Motivation:

Sometimes it is useful to disable recycling completely if memory constraints are very tight.

Modifications:

Allow to use -Dio.netty.recycler.maxCapacity=0 to disable recycling completely.

Result:

It's possible to disable recycling now.
This commit is contained in:
Norman Maurer 2015-08-27 11:08:27 +02:00
parent eb90e4256b
commit 910ae03792
2 changed files with 55 additions and 2 deletions

View File

@ -36,8 +36,17 @@ public abstract class Recycler<T> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class); private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class);
@SuppressWarnings("rawtypes")
private static final Handle NOOP_HANDLE = new Handle() {
@Override
public void recycle(Object object) {
// NOOP
}
};
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE); private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE);
private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement(); private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement();
// TODO: Some arbitrary large number - should adjust as we get more production experience.
private static final int DEFAULT_INITIAL_MAX_CAPACITY = 262144;
private static final int DEFAULT_MAX_CAPACITY; private static final int DEFAULT_MAX_CAPACITY;
private static final int INITIAL_CAPACITY; private static final int INITIAL_CAPACITY;
@ -45,7 +54,7 @@ public abstract class Recycler<T> {
// In the future, we might have different maxCapacity for different object types. // In the future, we might have different maxCapacity for different object types.
// e.g. io.netty.recycler.maxCapacity.writeTask // e.g. io.netty.recycler.maxCapacity.writeTask
// io.netty.recycler.maxCapacity.outboundBuffer // io.netty.recycler.maxCapacity.outboundBuffer
int maxCapacity = SystemPropertyUtil.getInt("io.netty.recycler.maxCapacity", 0); int maxCapacity = SystemPropertyUtil.getInt("io.netty.recycler.maxCapacity", DEFAULT_INITIAL_MAX_CAPACITY);
if (maxCapacity <= 0) { if (maxCapacity <= 0) {
// TODO: Some arbitrary large number - should adjust as we get more production experience. // TODO: Some arbitrary large number - should adjust as we get more production experience.
maxCapacity = 262144; maxCapacity = 262144;
@ -53,7 +62,11 @@ public abstract class Recycler<T> {
DEFAULT_MAX_CAPACITY = maxCapacity; DEFAULT_MAX_CAPACITY = maxCapacity;
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("-Dio.netty.recycler.maxCapacity: {}", DEFAULT_MAX_CAPACITY); if (DEFAULT_MAX_CAPACITY == 0) {
logger.debug("-Dio.netty.recycler.maxCapacity.maxCapacity: disabled");
} else {
logger.debug("-Dio.netty.recycler.maxCapacity.maxCapacity: {}", DEFAULT_MAX_CAPACITY);
}
} }
INITIAL_CAPACITY = Math.min(DEFAULT_MAX_CAPACITY, 256); INITIAL_CAPACITY = Math.min(DEFAULT_MAX_CAPACITY, 256);
@ -77,6 +90,9 @@ public abstract class Recycler<T> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final T get() { public final T get() {
if (maxCapacity == 0) {
return newObject((Handle<T>) NOOP_HANDLE);
}
Stack<T> stack = threadLocal.get(); Stack<T> stack = threadLocal.get();
DefaultHandle<T> handle = stack.pop(); DefaultHandle<T> handle = stack.pop();
if (handle == null) { if (handle == null) {
@ -87,6 +103,10 @@ public abstract class Recycler<T> {
} }
public final boolean recycle(T o, Handle<T> handle) { public final boolean recycle(T o, Handle<T> handle) {
if (handle == NOOP_HANDLE) {
return false;
}
DefaultHandle<T> h = (DefaultHandle<T>) handle; DefaultHandle<T> h = (DefaultHandle<T>) handle;
if (h.stack.parent != this) { if (h.stack.parent != this) {
return false; return false;

View File

@ -40,6 +40,15 @@ public class RecyclerTest {
object2.recycle(); object2.recycle();
} }
@Test
public void testRecycleDisable() {
DisabledRecyclableObject object = DisabledRecyclableObject.newInstance();
object.recycle();
DisabledRecyclableObject object2 = DisabledRecyclableObject.newInstance();
assertNotSame(object, object2);
object2.recycle();
}
static final class RecyclableObject { static final class RecyclableObject {
private static final Recycler<RecyclableObject> RECYCLER = new Recycler<RecyclableObject>() { private static final Recycler<RecyclableObject> RECYCLER = new Recycler<RecyclableObject>() {
@ -64,6 +73,30 @@ public class RecyclerTest {
} }
} }
static final class DisabledRecyclableObject {
private static final Recycler<DisabledRecyclableObject> RECYCLER = new Recycler<DisabledRecyclableObject>(-1) {
@Override
protected DisabledRecyclableObject newObject(Handle handle) {
return new DisabledRecyclableObject(handle);
}
};
private final Recycler.Handle handle;
private DisabledRecyclableObject(Recycler.Handle handle) {
this.handle = handle;
}
public static DisabledRecyclableObject newInstance() {
return RECYCLER.get();
}
public void recycle() {
RECYCLER.recycle(this, handle);
}
}
/** /**
* Test to make sure bug #2848 never happens again * Test to make sure bug #2848 never happens again
* https://github.com/netty/netty/issues/2848 * https://github.com/netty/netty/issues/2848