Use a dynamic pool size for the iterator cache

Many codepaths only end up with one iterator being used at a time and
most of the rest only get up to two being used so using a static pool of
three is wasteful. This also allows us to efficiently handle cases that
exceed 3 iterators in use. Overall this dramatically increases the hit rate
and results in less iterators being created.
This commit is contained in:
Travis Watkins 2012-08-19 19:59:58 -05:00
parent e7e643d83a
commit ccc760d629
2 changed files with 37 additions and 21 deletions

View File

@ -111,11 +111,13 @@ public class PathfinderGoalSelector {
// CraftBukkit - switch order // CraftBukkit - switch order
if (!this.a(pathfindergoalselectoritem, pathfindergoalselectoritem1) && this.b.contains(pathfindergoalselectoritem1)) { if (!this.a(pathfindergoalselectoritem, pathfindergoalselectoritem1) && this.b.contains(pathfindergoalselectoritem1)) {
// this.c.b(); // CraftBukkit - not in production code // this.c.b(); // CraftBukkit - not in production code
((UnsafeList.Itr) iterator).valid = false; // CraftBukkit - mark iterator for reuse
return false; return false;
} }
// CraftBukkit - switch order // CraftBukkit - switch order
} else if (!pathfindergoalselectoritem1.a.g() && this.b.contains(pathfindergoalselectoritem1)) { } else if (!pathfindergoalselectoritem1.a.g() && this.b.contains(pathfindergoalselectoritem1)) {
// this.c.b(); // CraftBukkit - not in production code // this.c.b(); // CraftBukkit - not in production code
((UnsafeList.Itr) iterator).valid = false; // CraftBukkit - mark iterator for reuse
return false; return false;
} }
} }

View File

@ -14,25 +14,28 @@ import java.util.RandomAccess;
// implementation of an ArrayList that offers a getter without range checks // implementation of an ArrayList that offers a getter without range checks
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable { public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
private static final long serialVersionUID = 8683452581112892190L; private static final long serialVersionUID = 8683452581112892191L;
private transient Object[] data; private transient Object[] data;
private int size; private int size;
private int initialCapacity; private int initialCapacity;
private Iterator[] iterPool = new Iterator[3]; private Iterator[] iterPool = new Iterator[1];
private int maxPool;
private int poolCounter; private int poolCounter;
public UnsafeList(int capacity) { public UnsafeList(int capacity, int maxIterPool) {
super(); super();
if (capacity < 0) capacity = 32; if (capacity < 0) capacity = 32;
int rounded = Integer.highestOneBit(capacity - 1) << 1; int rounded = Integer.highestOneBit(capacity - 1) << 1;
data = new Object[rounded]; data = new Object[rounded];
initialCapacity = rounded; initialCapacity = rounded;
maxPool = maxIterPool;
iterPool[0] = new Itr();
}
for (int i = 0; i < iterPool.length; i++) { public UnsafeList(int capacity) {
iterPool[i] = new Itr(); this(capacity, 5);
}
} }
public UnsafeList() { public UnsafeList() {
@ -143,31 +146,38 @@ public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAcc
copy.data = Java15Compat.Arrays_copyOf(data, size); copy.data = Java15Compat.Arrays_copyOf(data, size);
copy.size = size; copy.size = size;
copy.initialCapacity = initialCapacity; copy.initialCapacity = initialCapacity;
copy.iterPool = new Iterator[iterPool.length]; copy.iterPool = new Iterator[1];
copy.iterPool[0] = new Itr();
copy.maxPool = maxPool;
copy.poolCounter = 0;
return copy; return copy;
} }
public Iterator<E> iterator() { public Iterator<E> iterator() {
Itr iterator = null;
poolCounter = poolCounter++ % iterPool.length;
// Try to find an iterator that isn't in use // Try to find an iterator that isn't in use
for (Iterator iter : iterPool) { for (Iterator iter : iterPool) {
if (!((Itr) iter).valid) { if (!((Itr) iter).valid) {
iterator = (Itr) iter; Itr iterator = (Itr) iter;
break; iterator.reset();
return iterator;
} }
} }
// Couldn't find a free one, round robin replace one with a new iterator // Couldn't find one, see if we can grow our pool size
// This is done in the hope that the new one finishes so can be reused if (iterPool.length < maxPool) {
if (iterator == null) { Iterator[] newPool = new Iterator[iterPool.length + 1];
iterPool[poolCounter] = new Itr(); System.arraycopy(iterPool, 0, newPool, 0, iterPool.length);
iterator = (Itr) iterPool[poolCounter]; iterPool = newPool;
iterPool[iterPool.length - 1] = new Itr();
return iterPool[iterPool.length - 1];
} }
iterator.reset(); // Still couldn't find a free one, round robin replace one with a new iterator
return iterator; // This is done in the hope that the new one finishes so can be reused
poolCounter = ++poolCounter % iterPool.length;
iterPool[poolCounter] = new Itr();
return iterPool[poolCounter];
} }
private void rangeCheck(int index) { private void rangeCheck(int index) {
@ -192,6 +202,7 @@ public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAcc
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
os.writeObject(data[i]); os.writeObject(data[i]);
} }
os.writeInt(maxPool);
} }
private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
@ -203,13 +214,16 @@ public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAcc
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
data[i] = is.readObject(); data[i] = is.readObject();
} }
maxPool = is.readInt();
iterPool = new Iterator[1];
iterPool[0] = new Itr();
} }
private class Itr implements Iterator<E> { public class Itr implements Iterator<E> {
int index; int index;
int lastRet = -1; int lastRet = -1;
int expectedModCount = modCount; int expectedModCount = modCount;
boolean valid = true; public boolean valid = true;
public void reset() { public void reset() {
index = 0; index = 0;