Periodically clean up injectors in Spigot 1.6.4 and earlier.

This (may) fix a fairly serious memory leak.
This commit is contained in:
Kristian S. Stangeland 2014-01-17 02:51:22 +01:00
parent eea0d131bb
commit 90548f1092
2 changed files with 64 additions and 6 deletions

View File

@ -98,6 +98,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
public static final ReportType REPORT_CANNOT_UNREGISTER_PLUGIN = new ReportType("Unable to handle disabled plugin.");
public static final ReportType REPORT_PLUGIN_VERIFIER_ERROR = new ReportType("Verifier error: %s");
/**
* The number of ticks in a second.
*/
public static final int TICKS_PER_SECOND = 20;
/**
* Sets the inject hook type. Different types allow for maximum compatibility.
* @author Kristian
@ -129,7 +134,6 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
}
// The amount of time to wait until we actually unhook every player
private static final int TICKS_PER_SECOND = 20;
private static final int UNHOOK_DELAY = 5 * TICKS_PER_SECOND;
// Delayed unhook

View File

@ -24,6 +24,7 @@ import net.sf.cglib.proxy.NoOp;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.concurrency.PacketTypeSet;
import com.comphenix.protocol.error.DelegatedErrorReporter;
import com.comphenix.protocol.error.ErrorReporter;
@ -34,6 +35,8 @@ import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.PacketFilterBuilder;
import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.injector.PlayerLoggedOutException;
import com.comphenix.protocol.injector.packet.LegacyNetworkMarker;
import com.comphenix.protocol.injector.packet.PacketInjector;
@ -103,6 +106,10 @@ public class SpigotPacketInjector implements SpigotPacketListener {
// The proxy packet injector
private PacketInjector proxyPacketInjector;
// Background task
private static final int BACKGROUND_DELAY = 30 * PacketFilterManager.TICKS_PER_SECOND;
private int backgroundId;
/**
* Create a new spigot injector.
*/
@ -113,7 +120,7 @@ public class SpigotPacketInjector implements SpigotPacketListener {
this.queuedFilters = new PacketTypeSet();
this.reveivedFilters = new PacketTypeSet();
}
/**
* Retrieve the underlying listener invoker.
* @return The invoker.
@ -253,10 +260,55 @@ public class SpigotPacketInjector implements SpigotPacketListener {
throw new RuntimeException("Cannot register Spigot packet listener.", e);
}
// Remember to register background task
backgroundId = createBackgroundTask();
// If we succeed
return true;
}
/**
* Create and register a background task.
* @return The background task ID.
*/
private int createBackgroundTask() {
return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
@Override
public void run() {
cleanupInjectors();
}
}, BACKGROUND_DELAY, BACKGROUND_DELAY);
}
/**
* Ensure that all disconnected injectors are removed from memory.
*/
private void cleanupInjectors() {
for (NetworkObjectInjector injector : networkManagerInjector.values()) {
try {
if (injector.getSocket() != null && injector.getSocket().isClosed()) {
cleanupInjector(injector);
}
} catch (Exception e) {
reporter.reportMinimal(plugin, "cleanupInjectors", e);
// What?
cleanupInjector(injector);
}
}
}
/**
* Remove a given network object injector.
* @param injector - the injector.
*/
private void cleanupInjector(final NetworkObjectInjector injector) {
// Clean up
playerInjector.remove(injector.getPlayer());
playerInjector.remove(injector.getUpdatedPlayer());
networkManagerInjector.remove(injector.getNetworkManager());
}
/**
* Determine if the given method is a valid packet receiver or queued method.
* @param methodName - the expected name of the method.
@ -530,14 +582,12 @@ public class SpigotPacketInjector implements SpigotPacketListener {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
// Clean up
playerInjector.remove(injector.getPlayer());
playerInjector.remove(injector.getUpdatedPlayer());
networkManagerInjector.remove(injector.getNetworkManager());
cleanupInjector(injector);
}
}, CLEANUP_DELAY);
}
}
/**
* Invoked when a plugin wants to sent a packet.
* @param receiver - the packet receiver.
@ -609,6 +659,10 @@ public class SpigotPacketInjector implements SpigotPacketListener {
if (dynamicListener != null) {
cleanupListener();
}
if (backgroundId >= 0) {
Bukkit.getScheduler().cancelTask(backgroundId);
backgroundId = -1;
}
// Cleanup network marker
if (proxyPacketInjector != null) {