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.
Dieser Commit ist enthalten in:
Ursprung
e7e643d83a
Commit
ccc760d629
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren