explicitly remove smartpointers to decrease GC strain

This commit is contained in:
Alexey Kudravtsev
2013-07-29 14:11:23 +04:00
parent 3ac84bb7b7
commit e9c17aa89b
11 changed files with 88 additions and 20 deletions
@@ -60,4 +60,5 @@ public abstract class SmartPointerManager {
* @return true if both pointers point to the same PSI element.
*/
public abstract boolean pointToTheSameElement(@NotNull SmartPsiElementPointer pointer1, @NotNull SmartPsiElementPointer pointer2);
public abstract boolean removePointer(@NotNull SmartPsiElementPointer pointer);
}
@@ -205,8 +205,9 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable
@Nullable
public PsiElement getElement() {
if (myPointer.getProject().isDisposed()) return null;
return myPointer.getElement();
PsiElement element = myPointer.getElement();
SmartPointerManager.getInstance(myPointer.getProject()).removePointer(myPointer);
return element;
}
@Iconable.IconFlags
@@ -84,4 +84,9 @@ public class ClsElementInfo implements SmartPointerElementInfo {
public Project getProject() {
return myStubIndexReference.getProject();
}
@Override
public void cleanup() {
}
}
@@ -94,4 +94,9 @@ class FileElementInfo implements SmartPointerElementInfo {
public Project getProject() {
return myProject;
}
@Override
public void cleanup() {
}
}
@@ -80,4 +80,9 @@ class HardElementInfo implements SmartPointerElementInfo {
public Project getProject() {
return myProject;
}
@Override
public void cleanup() {
}
}
@@ -116,4 +116,10 @@ class InjectedSelfElementInfo extends SelfElementInfo {
SmartPointerElementInfo oElementInfo = ((SmartPsiElementPointerImpl)((InjectedSelfElementInfo)other).myInjectedFileRangeInHostFile).getElementInfo();
return myElementInfo.pointsToTheSameElementAs(oElementInfo);
}
@Override
public void cleanup() {
super.cleanup();
SmartPointerManager.getInstance(getProject()).removePointer(myInjectedFileRangeInHostFile);
}
}
@@ -205,6 +205,15 @@ public class SelfElementInfo implements SmartPointerElementInfo {
return ref == null ? null : ref.get();
}
@Override
public void cleanup() {
RangeMarker marker = getMarker();
if (marker != null) marker.dispose();
unfastenBelt(0);
setMarker(null);
mySyncMarkerIsValid = false;
}
private void setMarker(RangeMarker marker) {
myMarkerRef = marker == null ? null : new SoftReference<RangeMarker>(marker);
}
@@ -44,4 +44,6 @@ interface SmartPointerElementInfo {
@Nullable
Segment getRange();
@NotNull Project getProject();
void cleanup();
}
@@ -106,7 +106,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
}
}
private static final Key<Reference<SmartPsiElementPointer>> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY");
private static final Key<Reference<SmartPointerEx>> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY");
@Override
@NotNull
public <E extends PsiElement> SmartPsiElementPointer<E> createSmartPsiElementPointer(@NotNull E element) {
@@ -120,22 +120,26 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
if (containingFile != null && !containingFile.isValid() || containingFile == null && !element.isValid()) {
LOG.error("Invalid element:" + element);
}
SmartPsiElementPointer<E> cachedPointer = getCachedPointer(element);
SmartPointerEx<E> cachedPointer = getCachedPointer(element);
if (cachedPointer != null) {
containingFile = containingFile == null ? element.getContainingFile() : containingFile;
if (containingFile != null && areBeltsFastened(containingFile)) {
cachedPointer.fastenBelt(0, null);
}
return cachedPointer;
}
SmartPointerEx<E> pointer = new SmartPsiElementPointerImpl<E>(myProject, element, containingFile);
initPointer(pointer, containingFile);
element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference<SmartPsiElementPointer>(pointer));
element.putUserData(CACHED_SMART_POINTER_KEY, new SoftReference<SmartPointerEx>(pointer));
return pointer;
}
private static <E extends PsiElement> SmartPsiElementPointer<E> getCachedPointer(@NotNull E element) {
Reference<SmartPsiElementPointer> data = element.getUserData(CACHED_SMART_POINTER_KEY);
SmartPsiElementPointer cachedPointer = data == null ? null : data.get();
if (cachedPointer instanceof SmartPointerEx) {
PsiElement cachedElement = ((SmartPointerEx)cachedPointer).getCachedElement();
private static <E extends PsiElement> SmartPointerEx<E> getCachedPointer(@NotNull E element) {
Reference<SmartPointerEx> data = element.getUserData(CACHED_SMART_POINTER_KEY);
SmartPointerEx cachedPointer = data == null ? null : data.get();
if (cachedPointer != null) {
PsiElement cachedElement = cachedPointer.getCachedElement();
if (cachedElement != null && cachedElement != element) {
return null;
}
@@ -160,7 +164,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
synchronized (lock) {
List<SmartPointerEx> pointers = getPointers(containingFile);
if (pointers == null) {
pointers = new UnsafeWeakList<SmartPointerEx>(); // we synchronise access anyway by containingFile
pointers = new UnsafeWeakList<SmartPointerEx>(); // we synchronise access anyway
containingFile.putUserData(SMART_POINTERS_IN_PSI_FILE_KEY, pointers);
}
pointers.add(pointer);
@@ -171,14 +175,29 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
}
}
@Override
public boolean removePointer(@NotNull SmartPsiElementPointer pointer) {
synchronized (lock) {
PsiFile containingFile = pointer.getContainingFile();
if (containingFile == null) return false;
List<SmartPointerEx> pointers = getPointers(containingFile);
if (pointers == null) return false;
SmartPointerElementInfo info = ((SmartPsiElementPointerImpl)pointer).getElementInfo();
info.cleanup();
return pointers.remove(pointer);
}
}
private static List<SmartPointerEx> getPointers(@NotNull PsiFile containingFile) {
return containingFile.getUserData(SMART_POINTERS_IN_PSI_FILE_KEY);
}
@TestOnly
public int getPointersNumber(@NotNull PsiFile containingFile) {
List<SmartPointerEx> pointers = getPointers(containingFile);
return pointers == null ? 0 : pointers.size();
synchronized (lock) {
List<SmartPointerEx> pointers = getPointers(containingFile);
return pointers == null ? 0 : pointers.size();
}
}
private static boolean areBeltsFastened(@NotNull PsiFile file) {
@@ -98,9 +98,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
final PsiElement formatted = SourceTreeToPsiMap.treeElementToPsi(new CodeFormatterFacade(getSettings()).processElement(treeElement));
if (!canChangeWhiteSpacesOnly) {
return postProcessElement(formatted);
} else {
return formatted;
}
return formatted;
}
private PsiElement postProcessElement(@NotNull final PsiElement formatted) {
@@ -234,6 +233,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
postProcessText(file, new TextRange(info.fromStart ? 0 : startElement.getTextRange().getStartOffset(),
info.toEnd ? file.getTextLength() : endElement.getTextRange().getEndOffset()));
}
if (info.startPointer != null) smartPointerManager.removePointer(info.startPointer);
if (info.endPointer != null) smartPointerManager.removePointer(info.endPointer);
}
if (editor == null) {
@@ -794,11 +795,10 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
}
private static class RangeFormatInfo{
public final SmartPsiElementPointer startPointer;
public final SmartPsiElementPointer endPointer;
public final boolean fromStart;
public final boolean toEnd;
private final SmartPsiElementPointer startPointer;
private final SmartPsiElementPointer endPointer;
private final boolean fromStart;
private final boolean toEnd;
RangeFormatInfo(@Nullable SmartPsiElementPointer startPointer,
@Nullable SmartPsiElementPointer endPointer,
@@ -41,6 +41,8 @@ import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import com.intellij.ui.*;
import com.intellij.ui.components.JBTabbedPane;
import com.intellij.ui.content.Content;
@@ -1030,6 +1032,19 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
myModelTracker.removeListener(this);
myUpdateAlarm.cancelAllRequests();
}
disposeSmartPointers();
}
private void disposeSmartPointers() {
SmartPointerManager pointerManager = SmartPointerManager.getInstance(getProject());
for (Usage usage : myUsageNodes.keySet()) {
if (usage instanceof UsageInfo2UsageAdapter) {
SmartPsiElementPointer<?> pointer = ((UsageInfo2UsageAdapter)usage).getUsageInfo().getSmartPointer();
if (pointer != null) {
pointerManager.removePointer(pointer);
}
}
}
}
@Override