Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristof Marti2004-06-18 19:57:33 +0000
committerChristof Marti2004-06-18 19:57:33 +0000
commit7a1fadc7459a0717440d72e9bf0e789d20ce50ba (patch)
treed651d9f747e98bd36ddee36e2406b292f6c2d123
parent396e1a550da9397beab7d153e0c3c5d53e2f50ec (diff)
downloadeclipse.platform.text-7a1fadc7459a0717440d72e9bf0e789d20ce50ba.tar.gz
eclipse.platform.text-7a1fadc7459a0717440d72e9bf0e789d20ce50ba.tar.xz
eclipse.platform.text-7a1fadc7459a0717440d72e9bf0e789d20ce50ba.zip
Fix Bug 62662: [performance] OutOfMemoryError commenting StyledTextv20040618_1700
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineChangeHover.java2
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/DocumentLineDiffer.java113
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/LinkedRangeFactory.java88
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/RangeDifferencer.java31
4 files changed, 213 insertions, 21 deletions
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineChangeHover.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineChangeHover.java
index c1e00e5d6..d05229f33 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineChangeHover.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineChangeHover.java
@@ -292,7 +292,7 @@ public class LineChangeHover implements IAnnotationHover, IAnnotationHoverExtens
public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) {
IDocument document= viewer.getDocument();
if (document != null) {
- Point range= computeLineRange(viewer, lineNumber, 0, document.getNumberOfLines());
+ Point range= computeLineRange(viewer, lineNumber, 0, Math.max(0, document.getNumberOfLines() - 1));
if (range.x != -1 && range.y != -1)
return new LineRange(range.x, range.y - range.x + 1);
}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/DocumentLineDiffer.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/DocumentLineDiffer.java
index a6e99ccf9..fb7fd070a 100644
--- a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/DocumentLineDiffer.java
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/DocumentLineDiffer.java
@@ -49,6 +49,7 @@ import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
import org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.DocLineComparator;
import org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.RangeDifference;
import org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.RangeDifferencer;
+import org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.LinkedRangeFactory.LowMemoryException;
/**
* Standard implementation of <code>ILineDiffer</code> as an incremental diff engine. A
@@ -67,13 +68,66 @@ import org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.Ran
*/
public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnnotationModel {
+ /**
+ * Artificial line difference information indicating a change with an empty line as original text.
+ */
+ private static class LineChangeInfo implements ILineDiffInfo {
+
+ private static final String[] ORIGINAL_TEXT= new String[] { "\n" }; //$NON-NLS-1$
+
+ /*
+ * @see org.eclipse.jface.text.source.ILineDiffInfo#getRemovedLinesBelow()
+ */
+ public int getRemovedLinesBelow() {
+ return 0;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.ILineDiffInfo#getRemovedLinesAbove()
+ */
+ public int getRemovedLinesAbove() {
+ return 0;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.ILineDiffInfo#getChangeType()
+ */
+ public int getChangeType() {
+ return CHANGED;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.ILineDiffInfo#hasChanges()
+ */
+ public boolean hasChanges() {
+ return true;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.ILineDiffInfo#getOriginalText()
+ */
+ public String[] getOriginalText() {
+ return ORIGINAL_TEXT;
+ }
+ }
+
/** Tells whether this class is in debug mode. */
private static boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.ui.workbench.texteditor/debug/DocumentLineDiffer")); //$NON-NLS-1$//$NON-NLS-2$
+ /** Suspended state */
+ private static final int SUSPENDED= 0;
+ /** Initializing state */
+ private static final int INITIALIZING= 1;
+ /** Synchronized state */
+ private static final int SYNCHRONIZED= 2;
+
+ /** This differ's state */
+ private int fState= SUSPENDED;
+ /** Artificial line difference information indicating a change with an empty line as original text. */
+ private final ILineDiffInfo fLineChangeInfo= new LineChangeInfo();
+
/** The provider for the reference document. */
IQuickDiffReferenceProvider fReferenceProvider;
- /** Whether this differ is in sync with the model. */
- private boolean fIsSynchronized;
/** The number of clients connected to this model. */
private int fOpenConnections;
/** The current document being tracked. */
@@ -136,6 +190,9 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
*/
public ILineDiffInfo getLineInfo(int line) {
+ if (isSuspended())
+ return fLineChangeInfo;
+
// try cache first / speeds up linear search
RangeDifference last= fLastDifference;
if (last != null && last.rightStart() <= line && last.rightEnd() > line)
@@ -282,7 +339,7 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
* @return <code>true</code> if we are initialized and in sync with the document.
*/
private boolean isInitialized() {
- return fIsSynchronized;
+ return fState == SYNCHRONIZED;
}
/**
@@ -291,7 +348,16 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
* @return <code>true</code> if we are initialized and in sync with the document.
*/
public synchronized boolean isSynchronized() {
- return fIsSynchronized;
+ return fState == SYNCHRONIZED;
+ }
+
+ /**
+ * Returns <code>true</code> if the differ is suspended.
+ *
+ * @return <code>true</code> if the differ is suspended
+ */
+ private synchronized boolean isSuspended() {
+ return fState == SUSPENDED;
}
/**
@@ -324,7 +390,7 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
*/
synchronized void initialize() {
// make new incoming changes go into the queue of stored events, plus signal we can't restore.
- fIsSynchronized= false;
+ fState= INITIALIZING;
if (fRightDocument == null)
return;
@@ -454,7 +520,13 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
// 6: Do Da Diffing
DocLineComparator ref= new DocLineComparator(reference, null, false);
DocLineComparator act= new DocLineComparator(actual, null, false);
- List diffs= RangeDifferencer.findRanges(monitor, ref, act);
+ List diffs;
+ try {
+ diffs= RangeDifferencer.findRanges(monitor, ref, act);
+ } catch (LowMemoryException e) {
+ handleLowMemory(e);
+ return Status.CANCEL_STATUS;
+ }
// 7: Reset the model to the just gotten differences
// re-inject stored events to get up to date.
@@ -477,7 +549,7 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
if (fStoredEvents.isEmpty()) {
// we are done
fInitializationJob= null;
- fIsSynchronized= true;
+ fState= SYNCHRONIZED;
fLastDifference= null;
// inform blocking calls.
@@ -500,6 +572,9 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
clearModel();
initialize();
return Status.CANCEL_STATUS;
+ } catch (LowMemoryException e) {
+ handleLowMemory(e);
+ return Status.CANCEL_STATUS;
}
fireModelChanged();
@@ -634,6 +709,9 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
} catch (ConcurrentModificationException e) {
reinitOnError(e);
return;
+ } catch (LowMemoryException e) {
+ handleLowMemory(e);
+ return;
}
// inform listeners about change
@@ -672,8 +750,9 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
* Implementation of documentChanged, non synchronized.
*
* @param event the document event
+ * @throws LowMemoryException if the differ runs out of memory
*/
- void handleChanged(DocumentEvent event) throws BadLocationException {
+ void handleChanged(DocumentEvent event) throws BadLocationException, LowMemoryException {
/*
* Now, here we have a great example of object oriented programming.
*/
@@ -1177,7 +1256,7 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
*/
private void uninstall() {
synchronized (this) {
- fIsSynchronized= false;
+ fState= SUSPENDED;
fIgnoreDocumentEvents= true;
if (fInitializationJob != null)
fInitializationJob.cancel();
@@ -1293,10 +1372,13 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
fRightDocument.removeDocumentListener(this);
if (fLeftDocument != null)
fLeftDocument.removeDocumentListener(this);
+ fLeftDocument= null;
+ fLastDifference= null;
+ fStoredEvents.clear();
fDifferences.clear();
- fIsSynchronized= false;
+ fState= SUSPENDED;
fireModelChanged();
}
@@ -1309,4 +1391,15 @@ public class DocumentLineDiffer implements ILineDiffer, IDocumentListener, IAnno
fRightDocument.addDocumentListener(this);
initialize();
}
+
+ /**
+ * Handle low memory situation during diffing. Called from UI and jobs.
+ *
+ * @param e the low memory exception
+ */
+ private void handleLowMemory(LowMemoryException e) {
+ if (DEBUG)
+ System.err.println("Disabling QuickDiff:\n" + e); //$NON-NLS-1$
+ suspend();
+ }
}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/LinkedRangeFactory.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/LinkedRangeFactory.java
new file mode 100644
index 000000000..b39acd846
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/LinkedRangeFactory.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer;
+
+/**
+ * Memory-monitoring factory for <code>LinkedRangeDifference</code>.
+ *
+ * @since 3.0
+ */
+public class LinkedRangeFactory {
+
+ /**
+ * Exception that is thrown after the minimal allowed free memory is reached.
+ */
+ public static class LowMemoryException extends Exception {
+
+ /**
+ * Initialize without detail message.
+ */
+ public LowMemoryException() {
+ super();
+ }
+
+ /**
+ * Initialize with the given detail message.
+ *
+ * @param message the detail message
+ */
+ public LowMemoryException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Relative amount of memory that must be free in order to allow the creation of additional instances
+ */
+ private static final double THRESHOLD= 0.1;
+
+ /**
+ * Number of instantiations after which the amount of free memory is checked
+ */
+ private static final long CHECK_INTERVAL= 10000;
+
+ /**
+ * Number of instantiations
+ */
+ private long fCount= 0;
+
+ /**
+ * Create a new linked range difference with the given next range and operation.
+ *
+ * @param next the next linked range difference
+ * @param operation the operation
+ * @return the new linked range difference
+ * @throws LowMemoryException
+ */
+ public LinkedRangeDifference newRange(LinkedRangeDifference next, int operation) throws LowMemoryException {
+ check();
+ return new LinkedRangeDifference(next, operation);
+ }
+
+ /**
+ * After <code>CHECK_INTERVAL</code> calls check whether at least a fraction of <code>THRESHOLD</code>
+ * of the maximal available memory is free, otherwise throw an {@link LowMemoryException}.
+ *
+ * @throws LowMemoryException
+ */
+ private void check() throws LowMemoryException {
+ if (++fCount >= CHECK_INTERVAL) {
+ fCount= 0;
+
+ Runtime runtime= Runtime.getRuntime();
+ long maxMemory= runtime.maxMemory();
+ long maxFreeMemory= maxMemory - (runtime.totalMemory() - runtime.freeMemory());
+
+ if (((float) maxFreeMemory) / maxMemory < THRESHOLD)
+ throw new LowMemoryException();
+ }
+ }
+}
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/RangeDifferencer.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/RangeDifferencer.java
index 0b0829631..3dca97002 100644
--- a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/RangeDifferencer.java
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/quickdiff/compare/rangedifferencer/RangeDifferencer.java
@@ -14,6 +14,8 @@ import java.util.*;
import org.eclipse.jface.util.Assert;
+import org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.LinkedRangeFactory.LowMemoryException;
+
import org.eclipse.core.runtime.IProgressMonitor;
/**
@@ -56,8 +58,9 @@ public final class RangeDifferencer {
* @param left the left range comparator
* @param right the right range comparator
* @return an array of range differences, or an empty array if no differences were found
+ * @throws LowMemoryException if the differencer runs out of memory
*/
- public static RangeDifference[] findDifferences(IRangeComparator left, IRangeComparator right) {
+ public static RangeDifference[] findDifferences(IRangeComparator left, IRangeComparator right) throws LowMemoryException {
return findDifferences((IProgressMonitor)null, left, right);
}
@@ -70,9 +73,10 @@ public final class RangeDifferencer {
* @param left the left range comparator
* @param right the right range comparator
* @return an array of range differences, or an empty array if no differences were found
+ * @throws LowMemoryException if the differencer runs out of memory
* @since 2.0
*/
- public static RangeDifference[] findDifferences(IProgressMonitor pm, IRangeComparator left, IRangeComparator right) {
+ public static RangeDifference[] findDifferences(IProgressMonitor pm, IRangeComparator left, IRangeComparator right) throws LowMemoryException {
// assert that both IRangeComparators are of the same class
Assert.isTrue(right.getClass().equals(left.getClass()));
@@ -107,6 +111,7 @@ public final class RangeDifferencer {
return EMPTY_RESULT;
//System.out.println("findDifferences: " + maxDiagonal + " " + lower + " " + upper);
+ LinkedRangeFactory factory= new LinkedRangeFactory();
// for each value of the edit distance
for (int d= 1; d <= maxDiagonal; ++d) { // d is the current edit distance
@@ -129,13 +134,13 @@ public final class RangeDifferencer {
// move down
//
row= lastDiagonal[k + 1] + 1;
- edit= new LinkedRangeDifference(script[k + 1], LinkedRangeDifference.DELETE);
+ edit= factory.newRange(script[k + 1], LinkedRangeDifference.DELETE);
} else {
//
// move right
//
row= lastDiagonal[k - 1];
- edit= new LinkedRangeDifference(script[k - 1], LinkedRangeDifference.INSERT);
+ edit= factory.newRange(script[k - 1], LinkedRangeDifference.INSERT);
}
col= row + k - origin;
edit.fRightStart= row;
@@ -180,8 +185,9 @@ public final class RangeDifferencer {
* @param left the left range comparator
* @param right the right range comparator
* @return an array of range differences, or an empty array if no differences were found
+ * @throws LowMemoryException if the differencer runs out of memory
*/
- public static RangeDifference[] findDifferences(IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) {
+ public static RangeDifference[] findDifferences(IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) throws LowMemoryException {
return findDifferences(null, ancestor, left, right);
}
@@ -197,9 +203,10 @@ public final class RangeDifferencer {
* @param left the left range comparator
* @param right the right range comparator
* @return an array of range differences, or an empty array if no differences were found
+ * @throws LowMemoryException if the differencer runs out of memory
* @since 2.0
*/
- public static RangeDifference[] findDifferences(IProgressMonitor pm, IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) {
+ public static RangeDifference[] findDifferences(IProgressMonitor pm, IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) throws LowMemoryException {
if (ancestor == null)
return findDifferences(pm, left, right);
@@ -273,8 +280,9 @@ public final class RangeDifferencer {
* @param left the left range comparator
* @param right the right range comparator
* @return an array of range differences
+ * @throws LowMemoryException if the differencer runs out of memory
*/
- public static List findRanges(IRangeComparator left, IRangeComparator right) {
+ public static List findRanges(IRangeComparator left, IRangeComparator right) throws LowMemoryException {
return findRanges((IProgressMonitor)null, left, right);
}
@@ -287,9 +295,10 @@ public final class RangeDifferencer {
* @param left the left range comparator
* @param right the right range comparator
* @return an array of range differences
+ * @throws LowMemoryException if the differencer runs out of memory
* @since 2.0
*/
- public static List findRanges(IProgressMonitor pm, IRangeComparator left, IRangeComparator right) {
+ public static List findRanges(IProgressMonitor pm, IRangeComparator left, IRangeComparator right) throws LowMemoryException {
RangeDifference[] in= findDifferences(pm, left, right);
List out= new ArrayList();
@@ -329,8 +338,9 @@ public final class RangeDifferencer {
* @param left the left range comparator
* @param right the right range comparator
* @return an array of range differences
+ * @throws LowMemoryException if the differencer runs out of memory
*/
- public static List findRanges(IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) {
+ public static List findRanges(IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) throws LowMemoryException {
return findRanges(null, ancestor, left, right);
}
@@ -346,9 +356,10 @@ public final class RangeDifferencer {
* @param left the left range comparator
* @param right the right range comparator
* @return an array of range differences
+ * @throws LowMemoryException if the differencer runs out of memory
* @since 2.0
*/
- public static List findRanges(IProgressMonitor pm, IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) {
+ public static List findRanges(IProgressMonitor pm, IRangeComparator ancestor, IRangeComparator left, IRangeComparator right) throws LowMemoryException {
if (ancestor == null)
return findRanges(pm, left, right);

Back to the top