memleaks fixed + throw exception on leak

This commit is contained in:
Alexey Kudravtsev
2012-02-27 13:30:19 +04:00
parent 26e77f3db4
commit fa7e4eeb1a
6 changed files with 37 additions and 16 deletions
@@ -60,6 +60,7 @@ import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.runners.ExecutionUtil;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -147,7 +148,9 @@ public abstract class DebugProcessImpl implements DebugProcess {
private boolean myIsFailed = false;
protected DebuggerSession mySession;
@Nullable protected MethodReturnValueWatcher myReturnValueWatcher;
private final Alarm myStatusUpdateAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
private final Disposable myDisposable = Disposer.newDisposable();
private final Alarm myStatusUpdateAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myDisposable);
/** @noinspection FieldCanBeLocal*/
private volatile boolean myDebugProcessStarted = false;
@@ -553,7 +556,7 @@ public abstract class DebugProcessImpl implements DebugProcess {
String portString = myConnection.getAddress();
String hostString = myConnection.getHostName();
if (hostString == null || hostString.length() == 0) {
if (hostString == null || hostString.isEmpty()) {
//noinspection HardCodedStringLiteral
hostString = "localhost";
}
@@ -822,7 +825,7 @@ public abstract class DebugProcessImpl implements DebugProcess {
buf.append(DebuggerBundle.message("error.cannot.open.debugger.port")).append(" : ");
buf.append(e1.getClass().getName()).append(" ");
final String localizedMessage = e1.getLocalizedMessage();
if (localizedMessage != null && localizedMessage.length() > 0) {
if (localizedMessage != null && !localizedMessage.isEmpty()) {
buf.append('"');
buf.append(localizedMessage);
buf.append('"');
@@ -850,14 +853,14 @@ public abstract class DebugProcessImpl implements DebugProcess {
public void dispose() {
NodeRendererSettings.getInstance().removeListener(mySettingsListener);
Disposer.dispose(myStatusUpdateAlarm);
Disposer.dispose(myDisposable);
}
public DebuggerManagerThreadImpl getManagerThread() {
if (myDebuggerManagerThread == null) {
synchronized (this) {
if (myDebuggerManagerThread == null) {
myDebuggerManagerThread = new DebuggerManagerThreadImpl();
myDebuggerManagerThread = new DebuggerManagerThreadImpl(myDisposable);
}
}
}
@@ -21,11 +21,13 @@ import com.intellij.debugger.engine.managerThread.DebuggerCommand;
import com.intellij.debugger.engine.managerThread.DebuggerManagerThread;
import com.intellij.debugger.engine.managerThread.SuspendContextCommand;
import com.intellij.debugger.impl.InvokeAndWaitThread;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.ProgressIndicatorListenerAdapter;
import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.Alarm;
import com.sun.jdi.VMDisconnectedException;
import org.jetbrains.annotations.NotNull;
@@ -34,19 +36,21 @@ import org.jetbrains.annotations.TestOnly;
/**
* @author lex
*/
public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerCommandImpl> implements DebuggerManagerThread {
public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerCommandImpl> implements DebuggerManagerThread, Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebuggerManagerThreadImpl");
public static final int COMMAND_TIMEOUT = 3000;
private static final int RESTART_TIMEOUT = 500;
DebuggerManagerThreadImpl() {
//noinspection HardCodedStringLiteral
super();
DebuggerManagerThreadImpl(@NotNull Disposable parent) {
Disposer.register(parent, this);
}
public void dispose() {
}
@TestOnly
public static DebuggerManagerThreadImpl createTestInstance() {
return new DebuggerManagerThreadImpl();
public static DebuggerManagerThreadImpl createTestInstance(@NotNull Disposable parent) {
return new DebuggerManagerThreadImpl(parent);
}
public static boolean isManagerThread() {
@@ -94,14 +98,13 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerComma
* if worker thread is still processing the same command
* calls terminateCommand
*/
public void terminateAndInvoke(DebuggerCommandImpl command, int terminateTimeout) {
final DebuggerCommandImpl currentCommand = myEvents.getCurrentEvent();
invoke(command);
if (currentCommand != null) {
final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, this);
alarm.addRequest(new Runnable() {
public void run() {
if (currentCommand == myEvents.getCurrentEvent()) {
@@ -33,6 +33,7 @@ import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IconLoader;
import org.jetbrains.annotations.NotNull;
@@ -44,16 +45,19 @@ import java.awt.event.KeyEvent;
* @author spleaner
*/
public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
@Override
public boolean canRun(@NotNull final String executorId, @NotNull final RunProfile profile) {
return executorId.equals(DefaultRunExecutor.EXECUTOR_ID) &&
profile instanceof ModuleRunProfile &&
!(profile instanceof RunConfigurationWithSuppressedDefaultRunAction);
}
@Override
public void patch(JavaParameters javaParameters, RunnerSettings settings, final boolean beforeExecution) throws ExecutionException {
runCustomPatchers(javaParameters, settings, Executor.EXECUTOR_EXTENSION_NAME.findExtension(DefaultRunExecutor.class));
}
@Override
protected RunContentDescriptor doExecute(final Project project, final Executor executor, final RunProfileState state, final RunContentDescriptor contentToReuse,
final ExecutionEnvironment env) throws ExecutionException {
FileDocumentManager.getInstance().saveAllDocuments();
@@ -83,6 +87,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
onProcessStarted(env.getRunnerSettings(), executionResult);
final RunContentBuilder contentBuilder = new RunContentBuilder(project, this, executor);
Disposer.register(project, contentBuilder);
contentBuilder.setExecutionResult(executionResult);
contentBuilder.setEnvironment(env);
if (shouldAddDefaultActions) {
@@ -110,6 +115,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
final ProcessHandler processHandler = executionResult.getProcessHandler();
assert processHandler != null : executionResult;
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(final ProcessEvent event) {
processHandler.removeProcessListener(this);
controlBreakAction.unregisterCustomShortcutSet(consoleComponent);
@@ -129,6 +135,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
myProcessHandler = processHandler;
}
@Override
public void update(final AnActionEvent event) {
final Presentation presentation = event.getPresentation();
if (!isVisible()) {
@@ -157,6 +164,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
return super.isVisible() && ProcessProxyFactory.getInstance().isBreakGenLibraryAvailable();
}
@Override
public void actionPerformed(final AnActionEvent e) {
ProcessProxy proxy = ProcessProxyFactory.getInstance().getAttachedProxy(myProcessHandler);
if (proxy != null) {
@@ -170,6 +178,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
super(ExecutionBundle.message("run.configuration.exit.action.name"), null, IconLoader.getIcon("/actions/exit.png"), processHandler);
}
@Override
public void actionPerformed(final AnActionEvent e) {
ProcessProxy proxy = ProcessProxyFactory.getInstance().getAttachedProxy(myProcessHandler);
if (proxy != null) {
@@ -178,6 +187,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
}
}
@Override
@NotNull
public String getRunnerId() {
return "Run";
@@ -47,6 +47,6 @@ public class _LastInSuiteTest extends TestCase {
});
LeakHunter.checkProjectLeak(application);
Disposer.assertIsEmpty();
Disposer.assertIsEmpty(true);
}
}
@@ -114,8 +114,11 @@ public class Disposer {
}
public static void assertIsEmpty() {
assertIsEmpty(false);
}
public static void assertIsEmpty(boolean throwError) {
if (ourDebugMode) {
ourTree.assertIsEmpty();
ourTree.assertIsEmpty(throwError);
}
}
@@ -197,7 +197,7 @@ public final class ObjectTree<T> {
}
@SuppressWarnings({"UseOfSystemOutOrSystemErr", "HardCodedStringLiteral"})
public void assertIsEmpty() {
public void assertIsEmpty(boolean throwError) {
boolean firstObject = true;
for (T object : myRootObjects) {
@@ -219,6 +219,8 @@ public final class ObjectTree<T> {
if (trace != null) {
System.err.println("*** First seen at: ");
trace.printStackTrace();
if (throwError) throw new RuntimeException("Memory leak detected: " + object + " of class " + object.getClass()
+"\nSee the cause for the corresponding Disposer.register() stacktrace:\n",trace);
}
}