【问题标题】:java.util.LinkedList causing infinite loop/OutOfMemoryErrorjava.util.LinkedList 导致无限循环/OutOfMemoryError
【发布时间】:2009-11-18 04:43:56
【问题描述】:

我正在用我的一个类实现 Cloneable,我需要制作一个 java.util.LinkedList 的浅拷贝(是的,只是浅拷贝)来完成它。我尝试使用

myList.clone() //myList is a java.util.LinkedList<myType>

但这导致我的程序停止,所以我改用复制构造函数:

new LinkedList<myType>(myList)

但它仍然挂断。现在这仅发生在作为枚举的 myType 上,但现在我在非枚举类型上遇到了同样的错误,尽管现在我认为该类型具有内部枚举类型。这发生在 Sun 的 jdk 1.6 和 openjdk 1.6 上。我确定我做错了什么,但我不知道我会做什么会破坏 LinkedList。它不会抛出异常,直到它最终耗尽内存,(通常我会在这种情况发生之前杀死它)。无论如何,有什么想法可能导致这种情况吗?

这里是克隆方法:

public Note clone(){
    List<Accidental> retAcc=new LinkedList<Accidental>();
    for(Accidental acc:accidentals)retAcc.add(acc.clone());
    return new Note(retAcc,position,restFlag,new LinkedList<TieType>(beginTies),new LinkedList<TieType>(endTies),tripFlag,duration);
}

TieType 是一个枚举类型,Accidental 实现了 Cloneable 并且它的 clone() 方法复制如下。 position、restFlag、tripFlag 和 duration 都是原语

public Accidental clone(){
    return new Accidental(acType,fltPosition);

} 

acType 是一个内部枚举类型,fltPosition 是一个浮点数,它们初始化了仅有的两个字段。

当我调用 LinkedList 复制构造函数时,问题发生在 Note.clone() 方法的最后一行。这曾经是对 LinkedList.clone 的调用,但我对其进行了更改以试图避免此问题。这是此错误的堆栈跟踪(这里没有错误,因为我在线程冻结时暂停了线程,而不是等待它耗尽内存,但正如您所见,它位于 LinkedList 副本的中间构造函数)

LinkedList.(集合)行:115
Note.clone() 行:86
Note.simplify(int) 行:98
Note.split(int, List, List) 行:179
ManagedPart$Measure.adjustRemaining(int) 行:378 ManagedPart$Measure.add(Note) 行:349
ManagedPart$Measure.access$1(ManagedPart$Measure, Note) 行:345
ManagedPart.addNote(Note) 行:216
PartEditor$EditPanel$3.actionPerformed(ActionEvent) 行:104
JButton(AbstractButton).fireActionPerformed(ActionEvent) 行:2012
AbstractButton$Handler.actionPerformed(ActionEvent) 行:2335 DefaultButtonModel.fireActionPerformed(ActionEvent) 行:404
DefaultButtonModel.setPressed(boolean) 行:259
BasicButtonListener.mouseReleased(MouseEvent) 行:253
JButton(Component).processMouseEvent(MouseEvent) 行:6108
JButton(JComponent).processMouseEvent(MouseEvent) 行:3276
JButton(Component).processEvent(AWTEvent) 行:5873
JButton(Container).processEvent(AWTEvent) 行:2105
JButton(Component).dispatchEventImpl(AWTEvent) 行:4469
JButton(Container).dispatchEventImpl(AWTEvent) 行:2163
JButton(Component).dispatchEvent(AWTEvent) 行:4295
LightweightDispatcher.retargetMouseEvent(Component, int, MouseEvent) 行:4461
LightweightDispatcher.processMouseEvent(MouseEvent) 行:4125 LightweightDispatcher.dispatchEvent(AWTEvent) 行:4055
MusedDesktopClient(Container).dispatchEventImpl(AWTEvent) 行:2149
MusedDesktopClient(Window).dispatchEventImpl(AWTEvent) 行:2478
MusedDesktopClient(Component).dispatchEvent(AWTEvent) 行:4295
EventQueue.dispatchEvent(AWTEvent) 行:604
EventDispatchThread.pumpOneEventForFilters(int) 行:275
EventDispatchThread.pumpEventsForFilter(int, Conditional, EventFilter) 行:200
EventDispatchThread.pumpEventsForHierarchy(int, Conditional, Component) 行:190
EventDispatchThread.pumpEvents(int, Conditional) 行:185 EventDispatchThread.pumpEvents(Conditional) 行:177
EventDispatchThread.run() 行:138

最近,我在 Note.clone() i 的第一行中构造 LinkedList 时遇到了类似的问题。 e.

List<Accidental> retAcc=new LinkedList<Accidental>();

这是堆栈跟踪:

线程“AWT-EventQueue-0”java.lang.OutOfMemoryError 中的异常:Java 堆空间 在 java.util.LinkedList.(LinkedList.java:95) 在 com.mused.util.noteMgmt.Note.clone(Note.java:84) 在 com.mused.util.noteMgmt.Note.simplify(Note.java:98) 在 com.mused.util.noteMgmt.Note.split(Note.java:179) 在 com.mused.util.noteMgmt.ManagedPart$Measure.adjustRemaining(ManagedPart.java:378) 在 com.mused.util.noteMgmt.ManagedPart$Measure.insert(ManagedPart.java:335) 在 com.mused.util.noteMgmt.ManagedPart.insertNote(ManagedPart.java:223) 在 com.mused.gui.editor.PartEditor.currentIndexChanged(PartEditor.java:161) 在 com.mused.gui.NoteViewer.fireIndexChangeEvent(NoteViewer.java:178) 在 com.mused.gui.NoteViewer.setCurrentIndex(NoteViewer.java:417) 在 com.mused.gui.NoteViewer.updateSelected(NoteViewer.java:627) 在 com.mused.gui.NoteViewer.mouseMoved(NoteViewer.java:725) 在 java.awt.Component.processMouseMotionEvent(Component.java:6153) 在 javax.swing.JComponent.processMouseMotionEvent(JComponent.java:3294) 在 java.awt.Component.processEvent(Component.java:5877) 在 java.awt.Container.processEvent(Container.java:2105) 在 java.awt.Component.dispatchEventImpl(Component.java:4469) 在 java.awt.Container.dispatchEventImpl(Container.java:2163) 在 java.awt.Component.dispatchEvent(Component.java:4295) 在 java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4461) 在 java.awt.LightweightDispatcher.processMouseEvent(Container.java:4138) 在 java.awt.LightweightDispatcher.dispatchEvent(Container.java:4055) 在 java.awt.Container.dispatchEventImpl(Container.java:2149) 在 java.awt.Window.dispatchEventImpl(Window.java:2478) 在 java.awt.Component.dispatchEvent(Component.java:4295) 在 java.awt.EventQueue.dispatchEvent(EventQueue.java:604) 在 java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275) 在 java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200) 在 java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190) 在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185) 在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177) 在 java.awt.EventDispatchThread.run(EventDispatchThread.java:138)

【问题讨论】:

  • 你怎么知道 clone() 调用是罪魁祸首?请发布堆栈跟踪和您正在编写的足够多的类(实现 Cloneable 的类),以便我们查看发生了什么。
  • 包括整个 clone() 方法。
  • 你能写一个小测试用例重现问题吗?如果是,请在此处发布。
  • 我不确定是否可以在测试用例中重现它,因为它只会在某些时候发生,而且我不完全确定它是在什么条件下发生的。我不一定要根据正在发生的事情来寻找答案,因为这需要比我在此处实际给出的更多的有关该程序的知识。我只是在寻找关于什么样的一般问题可能导致 LinkedList 像这样停止而不是优雅地失败并出现异常的头脑风暴(我希望此类问题的列表相对较小)。

标签: java


【解决方案1】:

LinkedList::clone() 没有任何问题。如果它挂起,那么您的列表已损坏,以某种方式形成了一个循环链接。这是来自java/util/LinkedList.java的唯一相关代码的摘录:

for (Entry e = header.next; e != header; e = e.next)
    clone.add(e.element);

这与用于 LinkedList::toArray() 的算法相同,所以如果 clone() 挂起,那么应该这样:

System.out.println(Arrays.toString(myList.toArray()));

如果挂起,则您的列表已损坏。最可能的罪魁祸首是同步问题。 LinkedList 不是线程安全的。尝试像这样同步您的声明:

List&lt;myType&gt; myList = Collections.synchronizedList(new LinkedList&lt;myType&gt;());

【讨论】:

  • 我不是手动多线程。这是一个摇摆应用程序,所以我知道在后台进行多线程处理,但我的印象是我的所有代码都将在一个线程中执行,我不需要处理同步。那是错的吗?如果是这样,对 swing api 的哪些调用会导致产生一个新线程?
  • 顺便说一句,我从来没有暗示问题实际上出在 LinkedList 中,我知道这是我的错,我只是想知道我的代码如何导致 LinkedList 内部发生无限循环,并且你似乎已经回答了这个问题。
  • 我进行了切换,但我仍然遇到问题。实际上,想想看,我应该已经看到了,因为我在构建 empty LinkedList 时遇到了问题。
【解决方案2】:

您是否检查了 JVM 的内存分配选项?特别是-Xms-Xmx。您可能刚刚填满了默认分配的所有内存。你可以试试

-Xms256m -Xmx1024m

看看它是否在同一个地方失败?

【讨论】:

  • 我试过了,它仍然冻结。我不确定它现在是否会耗尽内存,尽管我猜它最终会。事情是被复制的列表包含非常少的数据(我已经用调试器验证了这一点)事实上,在我提到的第二个错误的情况下,我正在构建一个 empty 列表,当它冻结时。我觉得这个操作不应该花费这么多时间和内存,错误与否。
  • 出于好奇,我让我暂停的线程继续运行,实际上它最终确实耗尽了内存。肯定似乎有某种无限循环正在发生,我只是无法弄清楚可能导致它的原因。
【解决方案3】:

好的,所以我想通了。我曾以为我正在做的事情会导致 LinkedList 中的无限循环,但实际发生的是我编写了一个无限循环,其中包括对 LinkedList 方法的调用,而每当我暂停线程或系统耗尽内存,它是在 LinkedList 方法的执行期间。
显然,这些必须比循环内的其余代码或其他代码花费更长的时间来执行。因为当我查看堆栈跟踪时它总是在 LinkedList 中,所以我假设我以某种方式破坏了 LinkedList,而实际上我的损坏代码只是重复调用 LinkedList 方法,直到我停止它或内存不足。

【讨论】:

    猜你喜欢
    • 2020-08-27
    • 2021-05-07
    • 2012-08-24
    • 2020-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多