weather2
weather2 copied to clipboard
Fix Memory Leak Keeping Players Loaded
Changes StormObject#listEntitiesUnderClouds to use WeakReferences instead of retaining the player entirely.
Alternately, you could use this WeakArrayList wrapper I spent like 30 minutes too long on as your list instead to keep the API the same.
WeakArrayList Thing
import org.jetbrains.annotations.NotNull;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.function.UnaryOperator;
public class WeakArrayList<T> implements List<T> {
@Override
public int size() {
return internal.size();
}
@Override
public boolean isEmpty() {
return internal.isEmpty();
}
@Override
public boolean contains(Object o) {
return internal.contains(new WeakReference<>(o));
}
@NotNull
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < WeakArrayList.this.size();
}
@Override
public T next() {
return WeakArrayList.this.get(i++);
}
};
}
@NotNull
@Override
public Object[] toArray() {
return this.toArray(new Object[0]);
}
@SuppressWarnings("unchecked")
@NotNull
@Override
public <U> U[] toArray(@NotNull U[] a) {
WeakReference<T>[] array = internal.toArray(new WeakReference[0]);
U[] out = (U[]) Array.newInstance(a.getClass().arrayType(), internal.size());
for (int i = 0; i < array.length; i++) {
out[i] = (U) array[i].get();
}
return out;
}
public boolean add(T t) {
return internal.add(new WeakReference<>(t));
}
@Override
public boolean remove(Object o) {
return internal.remove(o);
}
@Override
public boolean containsAll(@NotNull Collection<?> c) {
return internal.containsAll(wrapIncomingCollection(c));
}
@Override
public boolean addAll(@NotNull Collection<? extends T> c) {
return internal.addAll((Collection<? extends WeakReference<T>>) wrapIncomingCollection(c));
}
@Override
public boolean addAll(int i, @NotNull Collection<? extends T> c) {
return internal.addAll(i, (Collection<? extends WeakReference<T>>) wrapIncomingCollection(c));
}
@Override
public boolean removeAll(@NotNull Collection<?> c) {
return internal.removeAll(wrapIncomingCollection(c));
}
@Override
public boolean retainAll(@NotNull Collection<?> c) {
return internal.retainAll(wrapIncomingCollection(c));
}
public void replaceAll(UnaryOperator<T> operator) {
internal.replaceAll((UnaryOperator<WeakReference<T>>) operator.compose(WeakReference<T>::get).andThen(WeakReference::new));
}
public void sort(Comparator<? super T> c) {
Comparator<? super WeakReference<T>> wrapped = (w1, w2) -> c.compare(w1.get(), w2.get());
internal.sort(wrapped);
}
@Override
public void clear() {
internal.clear();
}
@Override
public boolean equals(Object o) {
return internal.equals(new WeakReference<>(o));
}
@Override
public int hashCode() {
return internal.hashCode();
}
@Override
public T get(int index) {
return internal.get(index).get();
}
@Override
public T set(int index, T element) {
return internal.set(index, new WeakReference<>(element)).get();
}
@Override
public void add(int index, T element) {
internal.add(index, new WeakReference<>(element));
}
@Override
public T remove(int index) {
return internal.remove(index).get();
}
@Override
public int indexOf(Object o) {
return internal.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return internal.lastIndexOf(o);
}
@NotNull
@Override
public ListIterator<T> listIterator() {
return new ListIter(0);
}
@NotNull
@Override
public ListIterator<T> listIterator(int index) {
return new ListIter(index);
}
@NotNull
@Override
public List<T> subList(int fromIndex, int toIndex) {
WeakArrayList<T> ret = new WeakArrayList<>();
for (int i = fromIndex; i < toIndex; i++) {
ret.add(internal.get(i).get());
}
return ret;
}
private final List<WeakReference<T>> internal = new ArrayList<>();
private static <T> Collection<WeakReference<T>> wrapIncomingCollection(Collection<T> incoming) {
Collection<WeakReference<T>> mapped = new LinkedList<>();
for (T o : incoming) {
mapped.add(new WeakReference<>(o));
}
return mapped;
}
private class ListIter implements ListIterator<T> {
ListIter(int startIdx) {
this.i = startIdx;
}
private int i;
@Override
public boolean hasNext() {
return i < WeakArrayList.this.size();
}
@Override
public T next() {
return WeakArrayList.this.get(i++);
}
@Override
public boolean hasPrevious() {
return i >= 0;
}
@Override
public T previous() {
return WeakArrayList.this.get(--i);
}
@Override
public int nextIndex() {
return i + 1;
}
@Override
public int previousIndex() {
return i - 1;
}
@Override
public void remove() {
WeakArrayList.this.remove(i--);
}
@Override
public void set(T t) {
WeakArrayList.this.set(i, t);
}
@Override
public void add(T t) {
WeakArrayList.this.add(i, t);
}
}
}
I know this is going to be auto-closed, but I figured you should be aware of the memory leak. It held a few gigs hostage on my server.