Player not removed from entity tracking on disconnect
rjb3977 opened this issue ยท 6 comments
Minecraft: 1.18.2
Fabric Loader: 0.14.7
Fabric API: 0.55.1
Players are not removed from other worlds' entity trackers when they disconnect from a dedicated server. This results in a slow but steady memory leak, since Minecraft (stupidly) queues packets sent to a player after they disconnect; see net.minecraft.network.Connection#send.
To reproduce:
- Start a dedicated server
- Join the server
- Build a nether portal
- Go through the nether portal
- Use /forceload to load a chunk in the nether nearby the nether portal (to simulate another player being on the server and keeping the chunks near the portal loaded)
- Spawn a bunch of entities in that chunk
- Go back to the overworld
- Disconnect
- Wait a couple days for the server to run out of memory, or use a mixin like below to observe packets being sent long after the player has disconnected
Mixin
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import io.netty.channel.Channel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.Packet;
@Mixin(Connection.class)
public abstract class ConnectionMixin {
@Accessor("channel")
abstract Channel getChannel();
@Accessor("LOGGER")
abstract Logger getLogger();
@Inject(method = "send(Lnet/minecraft/network/protocol/Packet;Lio/netty/util/concurrent/GenericFutureListener;)V", at = @At("HEAD"))
public void send(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> callback, CallbackInfo callbackInfo) {
var channel = getChannel();
var logger = getLogger();
if (channel != null && !channel.isOpen()) {
logger.error("packet sent after disconnect");
// uncomment to show stack trace
// logger.error("packet stack trace", new Throwable(""));
}
}
}
Suggestion:
Currently, players are removed from entity tracking on respawn. Would it make more sense to do that in Player#remove? (Or ServerPlayer#remove, but that doesn't exist)
Vanilla assumes that the player can only track entities in its dimension, so only its dimension's entitys' trackers get that player removed but other dimensions' entity trackers do not. Going to fix it.
Your Mixin triggers even without ImmPtl. Vanilla seems stops entity tracking after closing the player connection.
Oh well that's a bit gross. I didn't test it in vanilla and didn't look into when vanilla actually removes players from entity tracking, that's my bad. With ImmPtl it seems like it keeps players in the entity trackers indefinitely though, which is still a problem (I think? I hope I didn't send you on a wild goose chase here). I can look into it more in the morning if you'd like a second set of eyes.
I fixed the issue that entity tracker does not remove respawned player. As I tested the server in IDE the connection object now can be GCed after the player disconnects and the memory leak should be fixed in the next version.
should be fixed in this version https://github.com/qouteall/ImmersivePortalsMod/releases/tag/v1.4.5-1.18