diff --git a/src/main/java/net/minestom/server/event/EventNodeImpl.java b/src/main/java/net/minestom/server/event/EventNodeImpl.java index d2c66379549..c535c452c92 100644 --- a/src/main/java/net/minestom/server/event/EventNodeImpl.java +++ b/src/main/java/net/minestom/server/event/EventNodeImpl.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.ref.WeakReference; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -445,14 +446,15 @@ void invalidate() { final var mappedNodeCache = node.registeredMappedNode; if (mappedNodeCache.isEmpty()) return null; Set> filters = new HashSet<>(mappedNodeCache.size()); - Map> handlers = new WeakHashMap<>(mappedNodeCache.size()); + Map>> handlers = new WeakHashMap<>(mappedNodeCache.size()); + // Retrieve all filters used to retrieve potential handlers for (var mappedEntry : mappedNodeCache.entrySet()) { final EventNodeImpl mappedNode = mappedEntry.getValue(); final Handle handle = (Handle) mappedNode.getHandle(eventType); if (!handle.hasListener()) continue; // Implicit update filters.add(mappedNode.filter); - handlers.put(mappedEntry.getKey(), handle); + handlers.put(mappedEntry.getKey(), new WeakReference<>(handle)); } // If at least one mapped node listen to this handle type, // loop through them and forward to mapped node if there is a match @@ -460,7 +462,8 @@ void invalidate() { final EventFilter[] filterList = filters.toArray(EventFilter[]::new); final BiConsumer, E> mapper = (filter, event) -> { final Object handler = filter.castHandler(event); - final Handle handle = handlers.get(handler); + final WeakReference> handleRef = handlers.get(handler); + final Handle handle = handleRef != null ? handleRef.get() : null; if (handle != null) handle.call(event); }; // Specialize the consumer depending on the number of filters to avoid looping diff --git a/src/test/java/net/minestom/server/instance/InstanceUnregisterIntegrationTest.java b/src/test/java/net/minestom/server/instance/InstanceUnregisterIntegrationTest.java index 63c11323bbb..ed7173f89fe 100644 --- a/src/test/java/net/minestom/server/instance/InstanceUnregisterIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/InstanceUnregisterIntegrationTest.java @@ -1,13 +1,16 @@ package net.minestom.server.instance; import net.minestom.server.coordinate.Pos; +import net.minestom.server.event.instance.InstanceTickEvent; import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.event.player.PlayerTickEvent; +import net.minestom.server.world.DimensionType; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import java.lang.ref.WeakReference; +import java.util.UUID; import static net.minestom.testing.TestUtils.waitUntilCleared; @@ -80,4 +83,23 @@ public void chunkGC(Env env) { chunk = null; waitUntilCleared(ref); } + + @Test + public void testGCWithEventsLambda(Env env) { + var ref = new WeakReference<>(new InstanceContainer(UUID.randomUUID(), DimensionType.OVERWORLD)); + env.process().instance().registerInstance(ref.get()); + + tmp(ref.get()); + + ref.get().tick(0); + env.process().instance().unregisterInstance(ref.get()); + + waitUntilCleared(ref); + } + + private void tmp(InstanceContainer instanceContainer) { + instanceContainer.eventNode().addListener(InstanceTickEvent.class, (e) -> { + var uuid = instanceContainer.getUniqueId(); + }); + } }