Bukkit插件中的内存泄漏

时间:2017-04-27 20:12:46

标签: java memory-leaks minecraft bukkit

在我的Spigot插件中,我使用重复任务每0.5秒更新一次播放器的广告资源。在运行代码较长时间后,我会得到java.lang.OutOfMemoryError: GC overhead limit exceeded

我做了一些调试并使用JProfiler查看导致内存泄漏的原因,并注意到越来越多的ItemStack。堆walker显示这是由更新库存的代码引起的。这是当前的代码:

public void updateInventory(Collection<? extends Player> players) {
    for (int i = 0; i < guiSize; i++) {
        ItemStack itemStack;
        if (serverItems.containsKey(i)) {
            itemStack = serverItems.get(i);
        } else {
            short color = GLASS_PANE_COLORS[RANDOM.nextInt(GLASS_PANE_COLORS.length - 1)];
            itemStack = new ItemStack(Material.STAINED_GLASS_PANE, 1, color);
            ItemMeta itemMeta = itemStack.getItemMeta();
            itemMeta.setDisplayName(ChatColor.RESET + "");
            itemStack.setItemMeta(itemMeta);
        }

        for (Player player : players) {
            player.getOpenInventory().getTopInventory().setItem(i, itemStack);
        }
    }
}

经过一些调试后,我发现删除行player.getOpenInventory().getTopInventory().setItem(i, itemStack)会阻止越来越多的ItemStack。

什么可能导致此内存泄漏?

编辑:

我已更改te代码,不为每个玻璃窗格制作新的ItemStack。相反,它现在将所有颜色存储在Map中,并从该地图获取ItemStack,以便放入库存中。这仍然不起作用,服务器将在一段时间后与OOME崩溃。

1 个答案:

答案 0 :(得分:0)

给定代码似乎是正确的,因为它不会导致观察到的内存泄漏。虽然没有显示,但预先生成ItemStacks的后续修改 - 一个更好的解决方案 - 也不会有任何贡献。

但是,您是否知道getOpenInventory()会返回播放器当前正在查看的广告资源,如果没有正在查看,则返回播放器的默认视图,这是他们制作的广告资源?您的方法是否有一个先决条件,即给定集合中的所有玩家都有一定的库存打开?如果一个或多个玩家正在查看烤箱,分配器等的库存会怎样?如果您想要始终访问播放器广告资源,则应使用getInventory()

我问,因为否则将项目设置为不同库存的不存在的插槽应该导致其他例外而不是您的OOM,尽管我不会在Spigot或Minecraft中对库存边界检查进行凭证。想一想,我简要介绍了最新的Spigot-Server代码。没有什么能引起内存泄漏的突出现象。

您在测试时是否加载了其他插件?如果是这样,请禁用除插件可能依赖的所有内容以外的所有内容。

我希望自己可以提供更多的见解,但我只能通过不需要更长时间调查的代码段来做很多事情。