eclipse-jdt / eclipse-jdt/eclipse.jdt.debug

Long UI freezes during debugging

Open
#143 1 comment 1 reaction 0 assignees View on GitHub
Dominant language
Java
Stars
23
Forks
68
Avg merge
1d 4h
Merged PRs (30d)
13

Description

Debugging remote services could lead to long freezes in the UI. The UI freeze monitor showed me a couple of traces like these:
```
at java.base@17.0.4/java.lang.Object.wait(Native Method)
at org.eclipse.jdi.internal.connect.PacketReceiveManager.waitForPacketAvailable(PacketReceiveManager.java:220)
at org.eclipse.jdi.internal.connect.PacketReceiveManager.getReply(PacketReceiveManager.java:165)
at org.eclipse.jdi.internal.connect.PacketReceiveManager.getReply(PacketReceiveManager.java:207)
at org.eclipse.jdi.internal.MirrorImpl.requestVM(MirrorImpl.java:195)
at org.eclipse.jdi.internal.MirrorImpl.requestVM(MirrorImpl.java:230)
at org.eclipse.jdi.internal.ArrayReferenceImpl.getValues(ArrayReferenceImpl.java:127)
at org.eclipse.jdi.internal.ArrayReferenceImpl.getValue(ArrayReferenceImpl.java:76)
at org.eclipse.jdt.internal.debug.core.model.JDIArrayEntryVariable.retrieveValue(JDIArrayEntryVariable.java:91)
at org.eclipse.jdt.internal.debug.core.model.JDIVariable.getCurrentValue(JDIVariable.java:74)
at org.eclipse.jdt.internal.debug.core.model.JDIVariable.getValue(JDIVariable.java:98)
at org.eclipse.jdt.internal.debug.core.model.JDIArrayEntryVariable.equals(JDIArrayEntryVariable.java:257)
at org.eclipse.jface.viewers.CustomHashtable.keyEquals(CustomHashtable.java:280)
at org.eclipse.jface.viewers.CustomHashtable.get(CustomHashtable.java:245)
at org.eclipse.jface.viewers.StructuredViewer.findItems(StructuredViewer.java:752)
at org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.findItem(InternalTreeModelViewer.java:1119)
at org.eclipse.debug.internal.ui.viewers.model.InternalTreeModelViewer.setElementData(InternalTreeModelViewer.java:1385)
at org.eclipse.debug.internal.ui.viewers.model.TreeModelLabelProvider.setElementData(TreeModelLabelProvider.java:325)
at org.eclipse.debug.internal.ui.viewers.model.LabelUpdate.performUpdate(LabelUpdate.java:140)
at org.eclipse.debug.internal.ui.viewers.model.TreeModelLabelProvider.lambda$0(TreeModelLabelProvider.java:412)
at org.eclipse.debug.internal.ui.viewers.model.TreeModelLabelProvider$$Lambda$1718/0x0000000801e73268.run(Unknown Source)
at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
```
and
```
at org.eclipse.jdi.internal.MirrorImpl.(MirrorImpl.java:84)
at org.eclipse.jdi.internal.ValueImpl.(ValueImpl.java:49)
at org.eclipse.jdi.internal.ObjectReferenceImpl.(ObjectReferenceImpl.java:76)
at org.eclipse.jdi.internal.ObjectReferenceImpl.(ObjectReferenceImpl.java:68)
at org.eclipse.jdi.internal.ObjectReferenceImpl.readObjectRefWithoutTag(ObjectReferenceImpl.java:638)
at org.eclipse.jdi.internal.ObjectReferenceImpl.readObjectRefWithTag(ObjectReferenceImpl.java:652)
at org.eclipse.jdi.internal.ArrayReferenceImpl.readObjectSequence(ArrayReferenceImpl.java:198)
at org.eclipse.jdi.internal.ArrayReferenceImpl.getValues(ArrayReferenceImpl.java:157)
at org.eclipse.jdi.internal.ArrayReferenceImpl.getValue(ArrayReferenceImpl.java:76)
at org.eclipse.jdt.internal.debug.core.model.JDIArrayEntryVariable.retrieveValue(JDIArrayEntryVariable.java:91)
at org.eclipse.jdt.internal.debug.core.model.JDIVariable.getCurrentValue(JDIVariable.java:74)
at org.eclipse.jdt.internal.debug.core.model.JDIVariable.getValue(JDIVariable.java:98)
at org.eclipse.jdt.internal.debug.core.model.JDIArrayEntryVariable.equals(JDIArrayEntryVariable.java:257)
at org.eclipse.debug.internal.ui.viewers.model.ViewerStateTracker.lambda$8(ViewerStateTracker.java:984)
at org.eclipse.debug.internal.ui.viewers.model.ViewerStateTracker$$Lambda$1728/0x0000000801eaa458.visit(Unknown Source)
at org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta.doAccept(ModelDelta.java:376)
at org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta.doAccept(ModelDelta.java:378)
at org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta.doAccept(ModelDelta.java:378)
at org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta.doAccept(ModelDelta.java:378)
at org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta.accept(ModelDelta.java:372)
at org.eclipse.debug.internal.ui.viewers.model.ViewerStateTracker.restorePendingStateOnUpdate(ViewerStateTracker.java:999)
at org.eclipse.debug.internal.ui.viewers.model.ChildrenUpdate.performUpdate(ChildrenUpdate.java:95)
at org.eclipse.debug.internal.ui.viewers.model.ChildrenUpdate.performUpdate(ChildrenUpdate.java:112)
at org.eclipse.debug.internal.ui.viewers.model.TreeModelContentProvider.performUpdates(TreeModelContentProvider.java:1830)
at org.eclipse.debug.internal.ui.viewers.model.TreeModelContentProvider.lambda$2(TreeModelContentProvider.java:1793)
at org.eclipse.debug.internal.ui.viewers.model.TreeModelContentProvider$$Lambda$1002/0x00000008015edc18.run(Unknown Source)
at org.eclipse.debug.internal.ui.viewers.model.TreeModelContentProvider$DelayedDoModelChangedJob.runInUIThread(TreeModelContentProvider.java:452)
```
and
```
at org.eclipse.jdi.internal.connect.PacketReceiveManager.waitForPacketAvailable(PacketReceiveManager.java:220)
at org.eclipse.jdi.internal.connect.PacketReceiveManager.getReply(PacketReceiveManager.java:165)
at org.eclipse.jdi.internal.connect.PacketReceiveManager.getReply(PacketReceiveManager.java:207)
at org.eclipse.jdi.internal.MirrorImpl.requestVM(MirrorImpl.java:195)
at org.eclipse.jdi.internal.MirrorImpl.requestVM(MirrorImpl.java:230)
at org.eclipse.jdi.internal.ArrayReferenceImpl.getValues(ArrayReferenceImpl.java:127)
at org.eclipse.jdi.internal.ArrayReferenceImpl.getValue(ArrayReferenceImpl.java:76)
at org.eclipse.jdt.internal.debug.core.model.JDIArrayEntryVariable.retrieveValue(JDIArrayEntryVariable.java:91)
at org.eclipse.jdt.internal.debug.core.model.JDIVariable.getCurrentValue(JDIVariable.java:74)
at org.eclipse.jdt.internal.debug.core.model.JDIVariable.getValue(JDIVariable.java:98)
at org.eclipse.jdt.internal.debug.core.model.JDIArrayEntryVariable.equals(JDIArrayEntryVariable.java:257)
at org.eclipse.jface.viewers.TreePath.equals(TreePath.java:158)
at org.eclipse.jface.viewers.TreePath.equals(TreePath.java:106)
at org.eclipse.debug.internal.ui.viewers.model.ViewerStateTracker$CompareRequestKey.equals(ViewerStateTracker.java:199)
at java.base@17.0.4/java.util.HashMap.removeNode(HashMap.java:818)
at java.base@17.0.4/java.util.HashMap.remove(HashMap.java:797)
at org.eclipse.debug.internal.ui.viewers.model.ViewerStateTracker.compareFinished(ViewerStateTracker.java:1412)
at org.eclipse.debug.internal.ui.viewers.model.ElementCompareRequest.lambda$0(ElementCompareRequest.java:82)
at org.eclipse.debug.internal.ui.viewers.model.ElementCompareRequest$$Lambda$2004/0x0000000802040b90.run(Unknown Source)
```
and
```
at org.eclipse.jdi.internal.connect.PacketReceiveManager.waitForPacketAvailable(PacketReceiveManager.java:220)
at org.eclipse.jdi.internal.connect.PacketReceiveManager.getReply(PacketReceiveManager.java:165)
at org.eclipse.jdi.internal.connect.PacketReceiveManager.getReply(PacketReceiveManager.java:207)
at org.eclipse.jdi.internal.MirrorImpl.requestVM(MirrorImpl.java:195)
at org.eclipse.jdi.internal.MirrorImpl.requestVM(MirrorImpl.java:230)
at org.eclipse.jdi.internal.StackFrameImpl.getValues(StackFrameImpl.java:140)
at org.eclipse.jdi.internal.StackFrameImpl.getValue(StackFrameImpl.java:78)
at org.eclipse.jdt.internal.debug.core.model.JDILocalVariable.retrieveValue(JDILocalVariable.java:64)
at org.eclipse.jdt.internal.debug.core.model.JDIVariable.getCurrentValue(JDIVariable.java:74)
at org.eclipse.jdt.internal.debug.core.model.JDIVariable.getValue(JDIVariable.java:98)
at org.eclipse.jdt.internal.debug.ui.JavaVarActionFilter.testAttribute(JavaVarActionFilter.java:171)
at org.eclipse.ui.internal.ActionExpression$ObjectStateExpression.preciselyMatches(ActionExpression.java:486)
at org.eclipse.ui.internal.ActionExpression$ObjectStateExpression.isEnabledFor(ActionExpression.java:455)
at org.eclipse.ui.internal.ActionExpression$OrExpression.isEnabledFor(ActionExpression.java:531)
at org.eclipse.ui.internal.ActionExpression$AndExpression.isEnabledFor(ActionExpression.java:126)
at org.eclipse.ui.internal.ActionExpression$SingleExpression.isEnabledFor(ActionExpression.java:678)
at org.eclipse.ui.internal.ActionExpression.isEnabledFor(ActionExpression.java:970)
at org.eclipse.ui.internal.ObjectActionContributor$ObjectContribution.isApplicableTo(ObjectActionContributor.java:337)
at org.eclipse.ui.internal.ObjectActionContributor.isApplicableTo(ObjectActionContributor.java:226)
at org.eclipse.ui.internal.ObjectContributorManager.isApplicableTo(ObjectContributorManager.java:302)
at org.eclipse.ui.internal.ObjectActionContributorManager.contributeObjectActions(ObjectActionContributorManager.java:89)
```
and so on ...

Even though, for remote debugging some sort of a slowness/slugishness is certainly expected, freezing the UI for multiple seconds is a very bad experience.
The stack traces are showing a very unfortunate situation, that the code actually tries to request things over the wire in the UI thread.
Most of the stack traces are related to JDIArrayEntryVariable.equals(...) method, but there are other codepaths as well.
What do you think, how can this be solved? Probably moving those evaluations in a separate background thread would be huge, invasive change, but some sort of caching of the requests could improve things - and even make the implementation less error prone, because I'm certain, that CustomHashtable is not well prepared to properly handle constantly changing keys. But the exact details, how and until when things can be cached, would be a challenge.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.