Various memory leak fixes
This commit is contained in:
parent
b3ed9db2c7
commit
a338fb27d3
@ -1,52 +1,209 @@
|
|||||||
package mineplex.core.memory;
|
package mineplex.core.memory;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import mineplex.core.MiniPlugin;
|
import mineplex.core.MiniPlugin;
|
||||||
import mineplex.core.updater.UpdateType;
|
import mineplex.core.updater.UpdateType;
|
||||||
import mineplex.core.updater.event.UpdateEvent;
|
import mineplex.core.updater.event.UpdateEvent;
|
||||||
import net.minecraft.server.v1_8_R3.CraftingManager;
|
import net.minecraft.server.v1_8_R3.CraftingManager;
|
||||||
|
import net.minecraft.server.v1_8_R3.Enchantment;
|
||||||
|
import net.minecraft.server.v1_8_R3.EnchantmentManager;
|
||||||
import net.minecraft.server.v1_8_R3.IInventory;
|
import net.minecraft.server.v1_8_R3.IInventory;
|
||||||
|
|
||||||
|
import net.minecraft.server.v1_8_R3.WorldServer;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
|
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.HumanEntity;
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.entity.EntityDamageByBlockEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
public class MemoryFix extends MiniPlugin
|
public class MemoryFix extends MiniPlugin
|
||||||
{
|
{
|
||||||
private static Field _intHashMap;
|
private static Field _intHashMap;
|
||||||
|
|
||||||
public MemoryFix(JavaPlugin plugin)
|
public MemoryFix(JavaPlugin plugin)
|
||||||
{
|
{
|
||||||
super("Memory Fix", plugin);
|
super("Memory Fix", plugin);
|
||||||
|
|
||||||
//_intHashMap = IntHashMap.class.
|
//_intHashMap = IntHashMap.class.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void fixLastDamageEventLeaks(UpdateEvent event)
|
||||||
|
{
|
||||||
|
if (event.getType() != UpdateType.SLOW)
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<World> worldList = Bukkit.getWorlds();
|
||||||
|
Set<World> worlds = new HashSet<>(worldList);
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (worlds.size() != worldList.size())
|
||||||
|
throw new RuntimeException("Error: Duplicated worlds?!?!");
|
||||||
|
|
||||||
|
|
||||||
|
for (World world : worlds)
|
||||||
|
{
|
||||||
|
WorldServer worldServer = ((CraftWorld) world).getHandle();
|
||||||
|
|
||||||
|
for (net.minecraft.server.v1_8_R3.Entity nmsentity : worldServer.entityList)
|
||||||
|
{
|
||||||
|
Entity entity = nmsentity.getBukkitEntity();
|
||||||
|
EntityDamageEvent lastDamageCause = entity.getLastDamageCause();
|
||||||
|
if (lastDamageCause != null)
|
||||||
|
{
|
||||||
|
Entity damaged = lastDamageCause.getEntity();
|
||||||
|
Entity damagerEntity = null;
|
||||||
|
Block damagerBlock = null;
|
||||||
|
if (lastDamageCause instanceof EntityDamageByEntityEvent)
|
||||||
|
damagerEntity = ((EntityDamageByEntityEvent) lastDamageCause).getDamager();
|
||||||
|
if (lastDamageCause instanceof EntityDamageByBlockEvent)
|
||||||
|
damagerBlock = ((EntityDamageByBlockEvent) lastDamageCause).getDamager();
|
||||||
|
|
||||||
|
boolean shouldRemove = false;
|
||||||
|
|
||||||
|
if (!damaged.isValid())
|
||||||
|
shouldRemove = true;
|
||||||
|
else if (damagerEntity != null)
|
||||||
|
{
|
||||||
|
if (!damagerEntity.isValid())
|
||||||
|
shouldRemove = true;
|
||||||
|
else if (!worlds.contains(damagerEntity.getWorld()))
|
||||||
|
shouldRemove = true;
|
||||||
|
}
|
||||||
|
else if (damagerBlock != null)
|
||||||
|
{
|
||||||
|
if (!worlds.contains(damagerBlock.getWorld()))
|
||||||
|
shouldRemove = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldRemove)
|
||||||
|
entity.setLastDamageCause(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object ENCHANTMENTMANAGER_D;
|
||||||
|
private static Field ENCHANTMENT_MODIFIER_THORNS_A;
|
||||||
|
private static Field ENCHANTMENT_MODIFIER_THORNS_B;
|
||||||
|
private static boolean ENCHANTMENTMANAGER_D_SUCCESFUL;
|
||||||
|
|
||||||
|
private static Object ENCHANTMENTMANAGER_E;
|
||||||
|
private static Field ENCHANTMENT_MODIFIER_ARTHROPODS_A;
|
||||||
|
private static Field ENCHANTMENT_MODIFIER_ARTHROPODS_B;
|
||||||
|
private static boolean ENCHANTMENTMANAGER_E_SUCCESFUL;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Field field = EnchantmentManager.class.getDeclaredField("d");
|
||||||
|
field.setAccessible(true);
|
||||||
|
ENCHANTMENTMANAGER_D = field.get(null);
|
||||||
|
ENCHANTMENT_MODIFIER_THORNS_A = ENCHANTMENTMANAGER_D.getClass().getDeclaredField("a");
|
||||||
|
ENCHANTMENT_MODIFIER_THORNS_A.setAccessible(true);
|
||||||
|
ENCHANTMENT_MODIFIER_THORNS_B = ENCHANTMENTMANAGER_D.getClass().getDeclaredField("b");
|
||||||
|
ENCHANTMENT_MODIFIER_THORNS_B.setAccessible(true);
|
||||||
|
ENCHANTMENTMANAGER_D_SUCCESFUL = true;
|
||||||
|
}
|
||||||
|
catch (ReflectiveOperationException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Field field = EnchantmentManager.class.getDeclaredField("e");
|
||||||
|
field.setAccessible(true);
|
||||||
|
ENCHANTMENTMANAGER_E = field.get(null);
|
||||||
|
ENCHANTMENT_MODIFIER_ARTHROPODS_A = ENCHANTMENTMANAGER_E.getClass().getDeclaredField("a");
|
||||||
|
ENCHANTMENT_MODIFIER_ARTHROPODS_A.setAccessible(true);
|
||||||
|
ENCHANTMENT_MODIFIER_ARTHROPODS_B = ENCHANTMENTMANAGER_E.getClass().getDeclaredField("b");
|
||||||
|
ENCHANTMENT_MODIFIER_ARTHROPODS_B.setAccessible(true);
|
||||||
|
ENCHANTMENTMANAGER_E_SUCCESFUL = true;
|
||||||
|
}
|
||||||
|
catch (ReflectiveOperationException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void fixEnchantmentManager(UpdateEvent event)
|
||||||
|
{
|
||||||
|
if (event.getType() != UpdateType.SLOW)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ENCHANTMENTMANAGER_D_SUCCESFUL)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
net.minecraft.server.v1_8_R3.Entity a = (net.minecraft.server.v1_8_R3.Entity) ENCHANTMENT_MODIFIER_THORNS_A.get(ENCHANTMENTMANAGER_D);
|
||||||
|
net.minecraft.server.v1_8_R3.Entity b = (net.minecraft.server.v1_8_R3.Entity) ENCHANTMENT_MODIFIER_THORNS_B.get(ENCHANTMENTMANAGER_D);
|
||||||
|
|
||||||
|
if ((a != null && !a.valid) || (b != null && !b.valid))
|
||||||
|
{
|
||||||
|
ENCHANTMENT_MODIFIER_THORNS_A.set(ENCHANTMENTMANAGER_D, null);
|
||||||
|
ENCHANTMENT_MODIFIER_THORNS_B.set(ENCHANTMENTMANAGER_D, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ReflectiveOperationException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ENCHANTMENTMANAGER_E_SUCCESFUL)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
net.minecraft.server.v1_8_R3.Entity a = (net.minecraft.server.v1_8_R3.Entity) ENCHANTMENT_MODIFIER_ARTHROPODS_A.get(ENCHANTMENTMANAGER_E);
|
||||||
|
net.minecraft.server.v1_8_R3.Entity b = (net.minecraft.server.v1_8_R3.Entity) ENCHANTMENT_MODIFIER_ARTHROPODS_B.get(ENCHANTMENTMANAGER_E);
|
||||||
|
|
||||||
|
if ((a != null && !a.valid) || (b != null && !b.valid))
|
||||||
|
{
|
||||||
|
ENCHANTMENT_MODIFIER_ARTHROPODS_A.set(ENCHANTMENTMANAGER_E, null);
|
||||||
|
ENCHANTMENT_MODIFIER_ARTHROPODS_B.set(ENCHANTMENTMANAGER_E, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ReflectiveOperationException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void fixInventoryLeaks(UpdateEvent event)
|
public void fixInventoryLeaks(UpdateEvent event)
|
||||||
{
|
{
|
||||||
if (event.getType() != UpdateType.SLOW)
|
if (event.getType() != UpdateType.SLOW)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (World world : Bukkit.getWorlds())
|
for (World world : Bukkit.getWorlds())
|
||||||
{
|
{
|
||||||
for (Object tileEntity : ((CraftWorld)world).getHandle().tileEntityList)
|
for (Object tileEntity : ((CraftWorld) world).getHandle().tileEntityList)
|
||||||
{
|
{
|
||||||
if (tileEntity instanceof IInventory)
|
if (tileEntity instanceof IInventory)
|
||||||
{
|
{
|
||||||
Iterator<HumanEntity> entityIterator = ((IInventory)tileEntity).getViewers().iterator();
|
Iterator<HumanEntity> entityIterator = ((IInventory) tileEntity).getViewers().iterator();
|
||||||
|
|
||||||
while (entityIterator.hasNext())
|
while (entityIterator.hasNext())
|
||||||
{
|
{
|
||||||
HumanEntity entity = entityIterator.next();
|
HumanEntity entity = entityIterator.next();
|
||||||
|
|
||||||
if (entity instanceof CraftPlayer && !((CraftPlayer)entity).isOnline())
|
if (entity instanceof CraftPlayer && !((CraftPlayer) entity).isOnline())
|
||||||
{
|
{
|
||||||
entityIterator.remove();
|
entityIterator.remove();
|
||||||
}
|
}
|
||||||
@ -54,17 +211,17 @@ public class MemoryFix extends MiniPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CraftingManager.getInstance().lastCraftView = null;
|
CraftingManager.getInstance().lastCraftView = null;
|
||||||
CraftingManager.getInstance().lastRecipe = null;
|
CraftingManager.getInstance().lastRecipe = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void fixEntityTrackerLeak(UpdateEvent event)
|
public void fixEntityTrackerLeak(UpdateEvent event)
|
||||||
{
|
{
|
||||||
if (event.getType() != UpdateType.SLOW)
|
if (event.getType() != UpdateType.SLOW)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// NEED TO FIX STUCK NETWORKMANAGERS.....
|
// NEED TO FIX STUCK NETWORKMANAGERS.....
|
||||||
/*
|
/*
|
||||||
for (World world : Bukkit.getWorlds())
|
for (World world : Bukkit.getWorlds())
|
||||||
|
Loading…
Reference in New Issue
Block a user