mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
memory optimization: reclaim storage for gced references
This commit is contained in:
@@ -38,7 +38,10 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectLocator;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.UserDataHolderEx;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl;
|
||||
@@ -104,12 +107,12 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() {
|
||||
@Override
|
||||
public void beforeWriteActionStart(Object action) {
|
||||
documentCommitThread.disable(action);
|
||||
documentCommitThread.disable("Write action started: "+ action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeActionFinished(Object action) {
|
||||
documentCommitThread.enable(action);
|
||||
documentCommitThread.enable("Write action finished: "+action);
|
||||
}
|
||||
}, myProject);
|
||||
documentCommitThread.enable("project open");
|
||||
@@ -336,13 +339,15 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
}
|
||||
}
|
||||
finally {
|
||||
//myDocumentCommitThread.log("in PDI.finishDoc: ",document, synchronously, success, myUncommittedDocuments);
|
||||
if (success) {
|
||||
myUncommittedDocuments.remove(document);
|
||||
|
||||
//myDocumentCommitThread.log("in PDI.finishDoc: removed doc",document, synchronously, success, myUncommittedDocuments);
|
||||
((DocumentImpl)document).normalizeRangeMarkers();
|
||||
InjectedLanguageUtil.commitAllInjectedDocuments(document, myProject);
|
||||
}
|
||||
myIsCommitInProgress = false;
|
||||
//myDocumentCommitThread.log("in PDI.finishDoc: exit",document, synchronously, success, myUncommittedDocuments);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
@@ -559,7 +564,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
if (file == null) continue;
|
||||
|
||||
if (file.isPhysical() && mySmartPointerManager != null) { // mock tests
|
||||
SmartPointerManagerImpl.fastenBelts(file, event.getOffset(), null);
|
||||
mySmartPointerManager.fastenBelts(file, event.getOffset(), null);
|
||||
}
|
||||
|
||||
final TextBlock textBlock = getTextBlock(file);
|
||||
@@ -598,7 +603,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec
|
||||
for (PsiFile file : files) {
|
||||
if (file == null || file instanceof PsiFileImpl && ((PsiFileImpl)file).getTreeElement() == null) continue;
|
||||
if (mySmartPointerManager != null) { // mock tests
|
||||
SmartPointerManagerImpl.unfastenBelts(file, event.getOffset());
|
||||
mySmartPointerManager.unfastenBelts(file, event.getOffset());
|
||||
}
|
||||
final TextBlock textBlock = getTextBlock(file);
|
||||
if (textBlock.isLocked()) continue;
|
||||
|
||||
@@ -872,7 +872,7 @@ public class FileManagerImpl implements FileManager {
|
||||
}
|
||||
|
||||
if (oldPsiFile != null && oldPsiFile.isPhysical()) {
|
||||
SmartPointerManagerImpl.fastenBelts(oldPsiFile, 0, null);
|
||||
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myManager.getProject())).fastenBelts(oldPsiFile, 0, null);
|
||||
}
|
||||
ApplicationManager.getApplication().runWriteAction(
|
||||
new ExternalChangeAction() {
|
||||
|
||||
+20
-59
@@ -30,19 +30,18 @@ import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.reference.SoftReference;
|
||||
import com.intellij.util.containers.UnsafeWeakList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl");
|
||||
|
||||
private static final Key<List<WeakReference<SmartPointerEx>>> SMART_POINTERS_IN_PSI_FILE_KEY = Key.create("SMART_POINTERS_IN_DOCUMENT_KEY");
|
||||
private static final Key<List<SmartPointerEx>> SMART_POINTERS_IN_PSI_FILE_KEY = Key.create("SMART_POINTERS_IN_DOCUMENT_KEY");
|
||||
private static final Key<Boolean> BELTS_ARE_FASTEN_KEY = Key.create("BELTS_ARE_FASTEN_KEY");
|
||||
|
||||
private final Project myProject;
|
||||
@@ -51,13 +50,13 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public static void fastenBelts(@NotNull PsiFile file, int offset, @Nullable RangeMarker cachedRangeMarker) {
|
||||
public void fastenBelts(@NotNull PsiFile file, int offset, @Nullable RangeMarker cachedRangeMarker) {
|
||||
synchronized (file) {
|
||||
if (areBeltsFastened(file)) return;
|
||||
|
||||
file.putUserData(BELTS_ARE_FASTEN_KEY, Boolean.TRUE);
|
||||
|
||||
List<WeakReference<SmartPointerEx>> pointers = getPointers(file);
|
||||
List<SmartPointerEx> pointers = getPointers(file);
|
||||
if (pointers == null) return;
|
||||
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(file.getProject());
|
||||
Document document = psiDocumentManager.getDocument(file);
|
||||
@@ -65,13 +64,9 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
((DocumentImpl)document).normalizeRangeMarkers();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < pointers.size(); i++) {
|
||||
WeakReference<SmartPointerEx> reference = pointers.get(i);
|
||||
SmartPointerEx pointer = reference.get();
|
||||
for (SmartPointerEx pointer : pointers) {
|
||||
if (pointer != null) {
|
||||
pointer.fastenBelt(offset, cachedRangeMarker);
|
||||
pointers.set(index++, reference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,15 +76,10 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
RangeMarker cachedMarker = getCachedRangeMarkerToInjectedFragment(injectedFile);
|
||||
fastenBelts(injectedFile, 0, cachedMarker);
|
||||
}
|
||||
|
||||
int size = pointers.size();
|
||||
for (int i = size - 1; i >= index; i--) {
|
||||
pointers.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static RangeMarker getCachedRangeMarkerToInjectedFragment(PsiFile injectedFile) {
|
||||
private static RangeMarker getCachedRangeMarkerToInjectedFragment(@NotNull PsiFile injectedFile) {
|
||||
PsiElement hostContext = injectedFile.getContext();
|
||||
RangeMarker cachedMarker = null;
|
||||
if (hostContext != null) {
|
||||
@@ -102,12 +92,12 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
return cachedMarker;
|
||||
}
|
||||
|
||||
public static void unfastenBelts(@NotNull PsiFile file, int offset) {
|
||||
public void unfastenBelts(@NotNull PsiFile file, int offset) {
|
||||
synchronized (file) {
|
||||
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(file.getProject());
|
||||
file.putUserData(BELTS_ARE_FASTEN_KEY, null);
|
||||
|
||||
List<WeakReference<SmartPointerEx>> pointers = getPointers(file);
|
||||
List<SmartPointerEx> pointers = getPointers(file);
|
||||
if (pointers == null) return;
|
||||
|
||||
Document document = psiDocumentManager.getDocument(file);
|
||||
@@ -115,13 +105,9 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
((DocumentImpl)document).normalizeRangeMarkers();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < pointers.size(); i++) {
|
||||
WeakReference<SmartPointerEx> reference = pointers.get(i);
|
||||
SmartPointerEx pointer = reference.get();
|
||||
for (SmartPointerEx pointer : pointers) {
|
||||
if (pointer != null) {
|
||||
pointer.unfastenBelt(offset);
|
||||
pointers.set(index++, reference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,15 +116,10 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
if (injectedFile == null) continue;
|
||||
unfastenBelts(injectedFile, 0);
|
||||
}
|
||||
|
||||
int size = pointers.size();
|
||||
for (int i = size - 1; i >= index; i--) {
|
||||
pointers.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void synchronizePointers(PsiFile file) {
|
||||
public static void synchronizePointers(@NotNull PsiFile file) {
|
||||
final Set<Language> languages = file.getViewProvider().getLanguages();
|
||||
for (Language language : languages) {
|
||||
final PsiFile f = file.getViewProvider().getPsi(language);
|
||||
@@ -148,17 +129,13 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static void _synchronizePointers(final PsiFile file) {
|
||||
List<WeakReference<SmartPointerEx>> pointers = getPointers(file);
|
||||
private static void _synchronizePointers(@NotNull PsiFile file) {
|
||||
List<SmartPointerEx> pointers = getPointers(file);
|
||||
if (pointers == null) return;
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < pointers.size(); i++) {
|
||||
WeakReference<SmartPointerEx> reference = pointers.get(i);
|
||||
SmartPointerEx pointer = reference.get();
|
||||
for (SmartPointerEx pointer : pointers) {
|
||||
if (pointer != null) {
|
||||
pointer.documentAndPsiInSync();
|
||||
pointers.set(index++, reference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,11 +145,6 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
if (injectedfile == null) continue;
|
||||
_synchronizePointers(injectedfile);
|
||||
}
|
||||
|
||||
int size = pointers.size();
|
||||
for (int i = size - 1; i >= index; i--) {
|
||||
pointers.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Key<Reference<SmartPsiElementPointer>> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY");
|
||||
@@ -197,7 +169,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
return pointer;
|
||||
}
|
||||
|
||||
private static <E extends PsiElement> SmartPsiElementPointer<E> getCachedPointer(E element) {
|
||||
private static <E extends PsiElement> SmartPsiElementPointer<E> getCachedPointer(@NotNull E element) {
|
||||
Reference<SmartPsiElementPointer> data = element.getUserData(CACHED_SMART_POINTER_KEY);
|
||||
return data == null ? null : data.get();
|
||||
}
|
||||
@@ -214,26 +186,15 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
return pointer;
|
||||
}
|
||||
|
||||
private static <E extends PsiElement> void initPointer(SmartPointerEx<E> pointer, PsiFile containingFile) {
|
||||
private static <E extends PsiElement> void initPointer(@NotNull SmartPointerEx<E> pointer, PsiFile containingFile) {
|
||||
if (containingFile == null) return;
|
||||
synchronized (containingFile) {
|
||||
//Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(containingFile);
|
||||
//todo
|
||||
//if (document != null) {
|
||||
// //[ven] this is a really NASTY hack; when no smart pointer is kept on UsageInfo then remove this conditional
|
||||
// if (!(element instanceof PsiFile)) {
|
||||
// PsiDocumentManagerImpl documentManager = (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject);
|
||||
// LOG.assertTrue(!documentManager.isUncommited(document) || documentManager.isCommittingDocument(document), "Document for : " +
|
||||
// containingFile + " is not committed");
|
||||
// }
|
||||
//}
|
||||
|
||||
List<WeakReference<SmartPointerEx>> pointers = getPointers(containingFile);
|
||||
List<SmartPointerEx> pointers = getPointers(containingFile);
|
||||
if (pointers == null) {
|
||||
pointers = new ArrayList<WeakReference<SmartPointerEx>>();
|
||||
pointers = new UnsafeWeakList<SmartPointerEx>(); // we synchronise access anyway by containingFile
|
||||
containingFile.putUserData(SMART_POINTERS_IN_PSI_FILE_KEY, pointers);
|
||||
}
|
||||
pointers.add(new WeakReference<SmartPointerEx>(pointer));
|
||||
pointers.add(pointer);
|
||||
|
||||
if (areBeltsFastened(containingFile)) {
|
||||
pointer.fastenBelt(0, null);
|
||||
@@ -241,11 +202,11 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<WeakReference<SmartPointerEx>> getPointers(@NotNull PsiFile containingFile) {
|
||||
private static List<SmartPointerEx> getPointers(@NotNull PsiFile containingFile) {
|
||||
return containingFile.getUserData(SMART_POINTERS_IN_PSI_FILE_KEY);
|
||||
}
|
||||
|
||||
private static boolean areBeltsFastened(final PsiFile file) {
|
||||
private static boolean areBeltsFastened(@NotNull PsiFile file) {
|
||||
return file.getUserData(BELTS_ARE_FASTEN_KEY) == Boolean.TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.util.containers;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link java.util.List} interface which:
|
||||
* <ul>
|
||||
* <li>Stores elements using weak semantics (see {@link java.lang.ref.WeakReference})</li>
|
||||
* <li>Automatically reclaims storage for garbage collected elements</li>
|
||||
* <li>Is NOT thread safe</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class UnsafeWeakList<T> extends AbstractList<T> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.util.containers.UnsafeWeakList");
|
||||
protected final WeakReferenceArray<T> myArray;
|
||||
|
||||
public UnsafeWeakList() {
|
||||
this(new WeakReferenceArray<T>());
|
||||
}
|
||||
|
||||
// For testing only
|
||||
UnsafeWeakList(@NotNull WeakReferenceArray<T> array) {
|
||||
myArray = array;
|
||||
}
|
||||
|
||||
public T get(int index) {
|
||||
return myArray.get(index);
|
||||
}
|
||||
|
||||
public boolean add(T element) {
|
||||
tryReduceCapacity(-1);
|
||||
myArray.add(element);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return super.contains(o);
|
||||
}
|
||||
|
||||
public boolean addIfAbsent(T element) {
|
||||
tryReduceCapacity(-1);
|
||||
if (contains(element)) return false;
|
||||
myArray.add(element);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void add(int index, T element) {
|
||||
tryReduceCapacity(-1);
|
||||
myArray.add(index, element);
|
||||
}
|
||||
|
||||
public T remove(int index) {
|
||||
tryReduceCapacity(-1);
|
||||
return myArray.remove(index);
|
||||
}
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return new MyIterator();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return myArray.size();
|
||||
}
|
||||
|
||||
public List<T> toStrongList() {
|
||||
List<T> result = new ArrayList<T>(myArray.size());
|
||||
myArray.toStrongCollection(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private int tryReduceCapacity(int trackIndex) {
|
||||
modCount++;
|
||||
if (canReduceCapacity()) {
|
||||
return myArray.reduceCapacity(trackIndex);
|
||||
}
|
||||
else {
|
||||
return probablyCompress(trackIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int myCompressCountdown = 10;
|
||||
private int probablyCompress(int trackIndex) {
|
||||
myCompressCountdown--;
|
||||
if (myCompressCountdown > 0) return trackIndex;
|
||||
int newIndex = myArray.compress(trackIndex);
|
||||
myCompressCountdown = myArray.size() + 10;
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
private boolean canReduceCapacity() {
|
||||
return WeakReferenceArray.MINIMUM_CAPACITY * 2 < myArray.getCapacity() &&
|
||||
myArray.getCapacity() > myArray.getAliveCount() * 3;
|
||||
}
|
||||
|
||||
protected class MyIterator implements Iterator<T> {
|
||||
private int myNextIndex = -1;
|
||||
private int myCurrentIndex = -1;
|
||||
private T myNextElement = null;
|
||||
private int myModCount = modCount;
|
||||
|
||||
public MyIterator() {
|
||||
findNext();
|
||||
}
|
||||
|
||||
protected void findNext() {
|
||||
myNextElement = null;
|
||||
while (myNextElement == null) {
|
||||
myNextIndex = myArray.nextValid(myNextIndex);
|
||||
if (myNextIndex >= myArray.size()) {
|
||||
myNextIndex = -1;
|
||||
myNextElement = null;
|
||||
return;
|
||||
}
|
||||
myNextElement = myArray.get(myNextIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return myNextElement != null;
|
||||
}
|
||||
|
||||
public T next() {
|
||||
if (modCount != myModCount) throw new ConcurrentModificationException();
|
||||
if (myNextElement == null) throw new NoSuchElementException();
|
||||
T element = myNextElement;
|
||||
myCurrentIndex = myNextIndex;
|
||||
findNext();
|
||||
return element;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (myCurrentIndex == -1) throw new IllegalStateException();
|
||||
myArray.remove(myCurrentIndex);
|
||||
final int removedIndex = myCurrentIndex;
|
||||
int newIndex = tryReduceCapacity(myNextIndex);
|
||||
myCurrentIndex = -1;
|
||||
myModCount = modCount;
|
||||
if (!hasNext()) return;
|
||||
if (newIndex < 0) {
|
||||
LOG.error(" was: " + myNextIndex +
|
||||
" got: " + newIndex +
|
||||
" size: " + myArray.size() +
|
||||
" current: " + removedIndex);
|
||||
}
|
||||
myNextIndex = newIndex;
|
||||
LOG.assertTrue(myArray.get(myNextIndex) == myNextElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,35 +15,41 @@
|
||||
*/
|
||||
package com.intellij.util.containers;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class WeakList<T> extends AbstractList<T> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.util.containers.WeakList");
|
||||
private final WeakReferenceArray<T> myArray;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link List} interface which:
|
||||
* <ul>
|
||||
* <li>Stores elements using weak semantics (see {@link java.lang.ref.WeakReference})</li>
|
||||
* <li>Automatically reclaims storage for garbage collected elements</li>
|
||||
* <li>Is thread safe</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WeakList<T> extends UnsafeWeakList<T> {
|
||||
public WeakList() {
|
||||
this(new WeakReferenceArray<T>());
|
||||
}
|
||||
|
||||
// For testing only
|
||||
WeakList(WeakReferenceArray<T> array) {
|
||||
myArray = array;
|
||||
WeakList(@NotNull WeakReferenceArray<T> array) {
|
||||
super(array);
|
||||
}
|
||||
|
||||
public T get(int index) {
|
||||
synchronized (myArray) {
|
||||
return myArray.get(index);
|
||||
return super.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean add(T element) {
|
||||
synchronized (myArray) {
|
||||
tryReduceCapacity(-1);
|
||||
myArray.add(element);
|
||||
return super.add(element);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,24 +61,19 @@ public class WeakList<T> extends AbstractList<T> {
|
||||
|
||||
public boolean addIfAbsent(T element) {
|
||||
synchronized (myArray) {
|
||||
tryReduceCapacity(-1);
|
||||
if (contains(element)) return false;
|
||||
myArray.add(element);
|
||||
return super.addIfAbsent(element);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void add(int index, T element) {
|
||||
synchronized (myArray) {
|
||||
tryReduceCapacity(-1);
|
||||
myArray.add(index, element);
|
||||
super.add(index, element);
|
||||
}
|
||||
}
|
||||
|
||||
public T remove(int index) {
|
||||
synchronized (myArray) {
|
||||
tryReduceCapacity(-1);
|
||||
return myArray.remove(index);
|
||||
return super.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +85,7 @@ public class WeakList<T> extends AbstractList<T> {
|
||||
}
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return new MyIterator();
|
||||
return new MySyncIterator();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
@@ -101,85 +102,16 @@ public class WeakList<T> extends AbstractList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private int tryReduceCapacity(int trackIndex) {
|
||||
modCount++;
|
||||
if (canReduceCapacity()) {
|
||||
return myArray.reduceCapacity(trackIndex);
|
||||
}
|
||||
else {
|
||||
return propablyCompress(trackIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int myCompressCountdown = 10;
|
||||
private int propablyCompress(int trackIndex) {
|
||||
myCompressCountdown--;
|
||||
if (myCompressCountdown > 0) return trackIndex;
|
||||
int newIndex = myArray.compress(trackIndex);
|
||||
myCompressCountdown = myArray.size() + 10;
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
private boolean canReduceCapacity() {
|
||||
return WeakReferenceArray.MINIMUM_CAPACITY*2 < myArray.getCapacity() &&
|
||||
myArray.getCapacity() > myArray.getAliveCount()*3;
|
||||
}
|
||||
|
||||
private class MyIterator implements Iterator<T> {
|
||||
private int myNextIndex = -1;
|
||||
private int myCurrentIndex = -1;
|
||||
private T myNextElement = null;
|
||||
private int myModCount = modCount;
|
||||
|
||||
public MyIterator() {
|
||||
findNext();
|
||||
}
|
||||
|
||||
private void findNext() {
|
||||
private class MySyncIterator extends MyIterator {
|
||||
protected void findNext() {
|
||||
synchronized (myArray) {
|
||||
myNextElement = null;
|
||||
while (myNextElement == null) {
|
||||
myNextIndex = myArray.nextValid(myNextIndex);
|
||||
if (myNextIndex >= myArray.size()) {
|
||||
myNextIndex = -1;
|
||||
myNextElement = null;
|
||||
return;
|
||||
}
|
||||
myNextElement = myArray.get(myNextIndex);
|
||||
}
|
||||
super.findNext();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return myNextElement != null;
|
||||
}
|
||||
|
||||
public T next() {
|
||||
if (modCount != myModCount) throw new ConcurrentModificationException();
|
||||
if (myNextElement == null) throw new NoSuchElementException();
|
||||
T element = myNextElement;
|
||||
myCurrentIndex = myNextIndex;
|
||||
findNext();
|
||||
return element;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
synchronized (myArray) {
|
||||
if (myCurrentIndex == -1) throw new IllegalStateException();
|
||||
myArray.remove(myCurrentIndex);
|
||||
final int removedIndex = myCurrentIndex;
|
||||
int newIndex = tryReduceCapacity(myNextIndex);
|
||||
myCurrentIndex = -1;
|
||||
myModCount = modCount;
|
||||
if (!hasNext()) return;
|
||||
if (newIndex < 0) {
|
||||
LOG.error(" was: " + myNextIndex +
|
||||
" got: " + newIndex +
|
||||
" size: " + myArray.size() +
|
||||
" current: " + removedIndex);
|
||||
}
|
||||
myNextIndex = newIndex;
|
||||
LOG.assertTrue(myArray.get(myNextIndex) == myNextElement);
|
||||
super.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user