从 HashMap 中删除对象时程序挂起?
Program hangs upon removal of a object from a HashMap?
我为 Minecraft 服务器开发插件。最近在我的测试服务器上,我在从 ArrayList 或 Hashmap 中删除对象时反复崩溃。
首先,它似乎只是从 ArrayList 中删除了一些东西。然而,它现在似乎能够在从任何 ArrayList/HashMap.
中移除某些东西时随机发生
在此特定实例中,代码行是 entlist.get(pl.getName()).remove(en);
,周围的代码是
for (LivingEntity en: remove) {
i++;
if (entlist.containsKey(pl.getName())) {
entlist.get(pl.getName()).remove(en);
}
if (i > 2000) {
try {
throw new Exception("Too many entities to remove!!");
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
entlist 是 HashMap<String, ArrayList<LivingEntity>> entlist = new HashMap<String, ArrayList<LivingEntity>>();
.
胎面转储明确列出 ArrayList#remove()
是问题所在。
[09:53:51 ERROR]: Current Thread: Server thread
[09:53:51 ERROR]: PID: 14 | Suspended: false | Native: false | State: RUNN
ABLE
[09:53:51 ERROR]: Stack:
[09:53:51 ERROR]: java.util.ArrayList.remove(ArrayList.java:481)
[09:53:51 ERROR]: a.e.run(Main.java:1786) //Line 1786 being the `entlist.get(pl.getName()).remove(en);` line from earlier.
Java版本:
C:\WINDOWS\system32>java -version
java version "1.7.0_11"
Java(TM) SE Runtime Environment (build 1.7.0_11-b21)
Java HotSpot(TM) Client VM (build 23.6-b04, mixed mode, sharing)
此外,由于有人在评论中询问,I've pastebinned the entire thread dump that Spigot puts out何时检测到冻结。
为什么简单地从 ArrayList/HashMap 中删除一个值会冻结整个服务器?
如果你说这是随机发生的,但总是在 List.remove 行上,这可能是并发问题,在你的程序的其他地方,另一个线程正在遍历列表。所以当你调用 remove() 时,你会遇到一个 ConcurrentModificationException
不完全清楚ArrayList的第481行是什么,但是假设它是this one,很难看出ArrayList.remove(...)
调用是如何"freezing"。
我有两种说法:
某些东西正在对 ArrayList
执行更新,但未正确同步。这可能会导致另一个线程看到 ArrayList
的陈旧/不一致状态,从而导致不可预测的行为。这个 可能 足以将 remove
操作置于无限循环中,尽管目前还不是很明显。
也可能是 HashMap
更新未同步。
应用程序完全没有冻结。相反,它需要 很长的时间 ... 因为你有一个非常大的数据结构 and/or 一个非常昂贵的 equals
操作。
您可以通过查看数据结构的大小 and/or 测量和记录该部分代码所用的时间来测试该理论(部分)。
我为 Minecraft 服务器开发插件。最近在我的测试服务器上,我在从 ArrayList 或 Hashmap 中删除对象时反复崩溃。
首先,它似乎只是从 ArrayList 中删除了一些东西。然而,它现在似乎能够在从任何 ArrayList/HashMap.
中移除某些东西时随机发生在此特定实例中,代码行是 entlist.get(pl.getName()).remove(en);
,周围的代码是
for (LivingEntity en: remove) {
i++;
if (entlist.containsKey(pl.getName())) {
entlist.get(pl.getName()).remove(en);
}
if (i > 2000) {
try {
throw new Exception("Too many entities to remove!!");
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
entlist 是 HashMap<String, ArrayList<LivingEntity>> entlist = new HashMap<String, ArrayList<LivingEntity>>();
.
胎面转储明确列出 ArrayList#remove()
是问题所在。
[09:53:51 ERROR]: Current Thread: Server thread
[09:53:51 ERROR]: PID: 14 | Suspended: false | Native: false | State: RUNN
ABLE
[09:53:51 ERROR]: Stack:
[09:53:51 ERROR]: java.util.ArrayList.remove(ArrayList.java:481)
[09:53:51 ERROR]: a.e.run(Main.java:1786) //Line 1786 being the `entlist.get(pl.getName()).remove(en);` line from earlier.
Java版本:
C:\WINDOWS\system32>java -version
java version "1.7.0_11"
Java(TM) SE Runtime Environment (build 1.7.0_11-b21)
Java HotSpot(TM) Client VM (build 23.6-b04, mixed mode, sharing)
此外,由于有人在评论中询问,I've pastebinned the entire thread dump that Spigot puts out何时检测到冻结。
为什么简单地从 ArrayList/HashMap 中删除一个值会冻结整个服务器?
如果你说这是随机发生的,但总是在 List.remove 行上,这可能是并发问题,在你的程序的其他地方,另一个线程正在遍历列表。所以当你调用 remove() 时,你会遇到一个 ConcurrentModificationException
不完全清楚ArrayList的第481行是什么,但是假设它是this one,很难看出ArrayList.remove(...)
调用是如何"freezing"。
我有两种说法:
某些东西正在对
ArrayList
执行更新,但未正确同步。这可能会导致另一个线程看到ArrayList
的陈旧/不一致状态,从而导致不可预测的行为。这个 可能 足以将remove
操作置于无限循环中,尽管目前还不是很明显。也可能是
HashMap
更新未同步。应用程序完全没有冻结。相反,它需要 很长的时间 ... 因为你有一个非常大的数据结构 and/or 一个非常昂贵的
equals
操作。您可以通过查看数据结构的大小 and/or 测量和记录该部分代码所用的时间来测试该理论(部分)。