project model: report error and remove remaining RootProvider's listeners when project is closed (IDEA-171323)

This doesn't fix the real problem but may help to diagnose it and fixes the memory leak.
This commit is contained in:
nik
2017-04-12 11:22:10 +03:00
parent d02dc29400
commit ea7fced5fa
2 changed files with 23 additions and 1 deletions
@@ -16,6 +16,7 @@
package com.intellij.openapi.roots.impl;
import com.intellij.ProjectTopics;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationAdapter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ProjectComponent;
@@ -62,7 +63,7 @@ import java.util.Set;
/**
* ProjectRootManager extended with ability to watch events.
*/
public class ProjectRootManagerComponent extends ProjectRootManagerImpl implements ProjectComponent {
public class ProjectRootManagerComponent extends ProjectRootManagerImpl implements ProjectComponent, Disposable {
private static final Logger LOG = Logger.getInstance(ProjectRootManagerComponent.class);
private boolean myPointerChangesDetected = false;
@@ -307,6 +308,11 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen
}
}
@Override
public void dispose() {
assertListenersAreDisposed();
}
private class AppListener extends ApplicationAdapter {
@Override
public void beforeWriteActionStart(@NotNull Object action) {
@@ -629,6 +629,22 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Pers
myJdkTableMultiListener.removeListener(jdkTableListener);
}
protected void assertListenersAreDisposed() {
if (!myRegisteredRootProviders.isEmpty()) {
StringBuilder details = new StringBuilder();
for (Map.Entry<RootProvider, Set<OrderEntry>> entry : myRegisteredRootProviders.entrySet()) {
details.append(" ").append(entry.getKey()).append(" referenced by ").append(entry.getValue().size()).append(" order entries:\n");
for (OrderEntry orderEntry : entry.getValue()) {
details.append(" ").append(orderEntry).append("\n");
}
}
LOG.error("Listeners for " + myRegisteredRootProviders.size() + " root providers aren't disposed:" + details);
for (RootProvider provider : myRegisteredRootProviders.keySet()) {
provider.removeRootSetChangedListener(myRootProviderChangeListener);
}
}
}
private class RootProviderChangeListener implements RootProvider.RootSetChangedListener {
private boolean myInsideRootsChange;