Skip to content

Commit 71c40a5

Browse files
committed
Lazy-load listener priority lists inside ListenerListInst to reduce memory usage
This avoids allocating many ArrayLists per Event that aren't always going to be used. The container for the priorities is also replaced with an array, to further reduce memory usage.
1 parent e0e273a commit 71c40a5

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

src/main/java/net/minecraftforge/eventbus/ListenerList.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
import java.util.Arrays;
1313
import java.util.Collections;
1414
import java.util.List;
15+
import java.util.Objects;
1516
import java.util.concurrent.Semaphore;
1617
import java.util.concurrent.atomic.AtomicReference;
1718

18-
1919
public class ListenerList {
2020
private static final List<ListenerList> allLists = new ArrayList<>();
2121
private static int maxSize = 0;
@@ -100,23 +100,24 @@ public static synchronized void unregisterAll(int id, IEventListener listener) {
100100
private static class ListenerListInst {
101101
private boolean rebuild = true;
102102
private AtomicReference<IEventListener[]> listeners = new AtomicReference<>();
103-
private final ArrayList<ArrayList<IEventListener>> priorities;
103+
private final @Nullable ArrayList<IEventListener>[] priorities;
104104
private ListenerListInst parent;
105105
private List<ListenerListInst> children;
106106
private final Semaphore writeLock = new Semaphore(1, true);
107107

108+
@SuppressWarnings("unchecked")
108109
private ListenerListInst() {
109-
int count = EventPriority.values().length;
110-
priorities = new ArrayList<>(count);
111-
112-
for (int x = 0; x < count; x++)
113-
priorities.add(new ArrayList<>());
110+
// Make a lazy-loaded array of lists containing listeners for each priority level.
111+
priorities = (ArrayList<IEventListener>[]) new ArrayList[EventPriority.values().length];
114112
}
115113

116114
public void dispose() {
117115
writeLock.acquireUninterruptibly();
118-
priorities.forEach(ArrayList::clear);
119-
priorities.clear();
116+
for (@Nullable ArrayList<IEventListener> priority : priorities) {
117+
if (priority != null)
118+
priority.clear();
119+
}
120+
Arrays.fill(priorities, null);
120121
writeLock.release();
121122
parent = null;
122123
listeners = null;
@@ -141,7 +142,7 @@ private ListenerListInst(ListenerListInst parent) {
141142
*/
142143
public ArrayList<IEventListener> getListeners(EventPriority priority) {
143144
writeLock.acquireUninterruptibly();
144-
ArrayList<IEventListener> ret = new ArrayList<>(priorities.get(priority.ordinal()));
145+
ArrayList<IEventListener> ret = new ArrayList<>(getListenersForPriority(priority));
145146
writeLock.release();
146147
if (parent != null)
147148
ret.addAll(parent.getListeners(priority));
@@ -193,7 +194,7 @@ private void buildCache() {
193194
ArrayList<IEventListener> ret = new ArrayList<>();
194195
Arrays.stream(EventPriority.values()).forEach(value -> {
195196
List<IEventListener> listeners = getListeners(value);
196-
if (listeners.size() > 0) {
197+
if (!listeners.isEmpty()) {
197198
ret.add(value); //Add the priority to notify the event of it's current phase.
198199
ret.addAll(listeners);
199200
}
@@ -205,15 +206,26 @@ private void buildCache() {
205206
public void register(EventPriority priority, IEventListener listener) {
206207
if (listener == null) return;
207208
writeLock.acquireUninterruptibly();
208-
priorities.get(priority.ordinal()).add(listener);
209+
getListenersForPriority(priority).add(listener);
209210
writeLock.release();
210211
this.forceRebuild();
211212
}
212213

213214
public void unregister(IEventListener listener) {
214215
writeLock.acquireUninterruptibly();
215-
priorities.stream().filter(list -> list.remove(listener)).forEach(list -> this.forceRebuild());
216+
Arrays.stream(priorities)
217+
.filter(Objects::nonNull)
218+
.filter(list -> list.remove(listener))
219+
.forEach(list -> this.forceRebuild());
216220
writeLock.release();
217221
}
222+
223+
private ArrayList<IEventListener> getListenersForPriority(EventPriority priority) {
224+
var listenersForPriority = priorities[priority.ordinal()];
225+
if (listenersForPriority == null)
226+
listenersForPriority = priorities[priority.ordinal()] = new ArrayList<>();
227+
228+
return listenersForPriority;
229+
}
218230
}
219231
}

0 commit comments

Comments
 (0)