fix memory leak

Signed-off-by: pengzhile <pengzhile@gmail.com>
This commit is contained in:
pengzhile 2020-11-13 22:10:51 +08:00
parent ba352d925b
commit ffc96d454a
11 changed files with 120 additions and 90 deletions

View File

@ -1,6 +1,6 @@
# Reset Your IDE Eval Information # Reset Your IDE Eval Information
1. Download and install plugin from [Download Link](https://plugins.zhile.io/files/ide-eval-resetter-2.1.3.zip). 1. Download and install plugin from [Download Link](https://plugins.zhile.io/files/ide-eval-resetter-2.1.5.zip).
* Alternative installation method: * Alternative installation method:
* Add "Custom Plugin Repository": `https://plugins.zhile.io` manually (`Settings/Preferences` -> `Plugins`) * Add "Custom Plugin Repository": `https://plugins.zhile.io` manually (`Settings/Preferences` -> `Plugins`)
* Search and install plugin: `IDE Eval Reset` * Search and install plugin: `IDE Eval Reset`

View File

@ -4,10 +4,10 @@ plugins {
} }
group 'io.zhile.research.intellij' group 'io.zhile.research.intellij'
version '2.1.4' version '2.1.5'
sourceCompatibility = 1.8 sourceCompatibility = 1.7
targetCompatibility = 1.8 targetCompatibility = 1.7
repositories { repositories {
mavenCentral() mavenCentral()
@ -29,6 +29,8 @@ intellij {
patchPluginXml { patchPluginXml {
changeNotes """<pre> changeNotes """<pre>
Release v2.1.5
1. fix memory leak
Release v2.1.4 Release v2.1.4
1. fix reference 1. fix reference
Release v2.1.3 Release v2.1.3

View File

@ -16,7 +16,6 @@ import io.zhile.research.intellij.ier.component.ResetTimer;
import io.zhile.research.intellij.ier.helper.Constants; import io.zhile.research.intellij.ier.helper.Constants;
import io.zhile.research.intellij.ier.helper.CustomRepository; import io.zhile.research.intellij.ier.helper.CustomRepository;
import io.zhile.research.intellij.ier.helper.PluginHelper; import io.zhile.research.intellij.ier.helper.PluginHelper;
import io.zhile.research.intellij.ier.helper.ProjectHelper;
import io.zhile.research.intellij.ier.tw.MainToolWindowFactory; import io.zhile.research.intellij.ier.tw.MainToolWindowFactory;
import io.zhile.research.intellij.ier.ui.dialog.MainDialog; import io.zhile.research.intellij.ier.ui.dialog.MainDialog;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -35,7 +34,7 @@ public class ResetAction extends AnAction implements DumbAware {
@Override @Override
public void actionPerformed(@NotNull AnActionEvent e) { public void actionPerformed(@NotNull AnActionEvent e) {
Project project = ProjectHelper.getProject(e); Project project = e.getProject();
Notification notification = NOTIFICATION_KEY.getData(e.getDataContext()); Notification notification = NOTIFICATION_KEY.getData(e.getDataContext());
if (null != notification) { if (null != notification) {

View File

@ -14,6 +14,11 @@ public class RestartAction extends AnAction implements DumbAware {
@Override @Override
public void actionPerformed(@NotNull AnActionEvent e) { public void actionPerformed(@NotNull AnActionEvent e) {
ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().restart()); ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().restart();
}
});
} }
} }

View File

@ -8,13 +8,13 @@ import com.intellij.openapi.util.SystemInfo;
import io.zhile.research.intellij.ier.helper.Constants; import io.zhile.research.intellij.ier.helper.Constants;
import io.zhile.research.intellij.ier.helper.NotificationHelper; import io.zhile.research.intellij.ier.helper.NotificationHelper;
import io.zhile.research.intellij.ier.helper.ReflectionHelper; import io.zhile.research.intellij.ier.helper.ReflectionHelper;
import org.jdom.Attribute;
import org.jdom.Element; import org.jdom.Element;
import java.io.File; import java.io.File;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.prefs.BackingStoreException; import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
@ -33,27 +33,40 @@ public class Resetter {
File evalDir = getEvalDir(); File evalDir = getEvalDir();
if (evalDir.exists()) { if (evalDir.exists()) {
File[] files = evalDir.listFiles((dir, name) -> name.endsWith(".key")); File[] files = evalDir.listFiles();
if (files == null) { if (files == null) {
NotificationHelper.showError(null, "List eval license file failed!"); NotificationHelper.showError(null, "List eval license file failed!");
} else { } else {
Arrays.stream(files).forEach(file -> list.add(new LicenseFileRecord(file))); for (File file : files) {
if (!file.getName().endsWith(".key")) {
continue;
}
list.add(new LicenseFileRecord(file));
}
} }
} }
Element state = PropertyRecord.PROPS.getState(); Element state = PropertyRecord.PROPS.getState();
if (state != null) { if (state != null) {
state.getChildren().stream().filter(element -> { Attribute attrName, attrValue;
for (Element element : state.getChildren()) {
if (!element.getName().equals("property")) { if (!element.getName().equals("property")) {
return false; continue;
} }
if (element.getAttribute("name") == null || element.getAttribute("value") == null) { attrName = element.getAttribute("name");
return false; attrValue = element.getAttribute("value");
if (attrName == null || attrValue == null) {
continue;
} }
return element.getAttribute("name").getValue().startsWith(EVAL_KEY); if (!attrName.getValue().startsWith(EVAL_KEY)) {
}).forEach(element -> list.add(new PropertyRecord(element.getAttribute("name").getValue()))); continue;
}
list.add(new PropertyRecord(attrName.getValue()));
}
} }
PreferenceRecord[] prefsValue = new PreferenceRecord[]{ PreferenceRecord[] prefsValue = new PreferenceRecord[]{
@ -61,7 +74,13 @@ public class Resetter {
new PreferenceRecord(NEW_MACHINE_ID_KEY), new PreferenceRecord(NEW_MACHINE_ID_KEY),
new PreferenceRecord(DEVICE_ID_KEY), new PreferenceRecord(DEVICE_ID_KEY),
}; };
Arrays.stream(prefsValue).filter(record -> record.getValue() != null).forEach(list::add); for (PreferenceRecord record : prefsValue) {
if (record.getValue() == null) {
continue;
}
list.add(record);
}
try { try {
List<String> prefsList = new ArrayList<>(); List<String> prefsList = new ArrayList<>();
@ -79,12 +98,16 @@ public class Resetter {
} }
} }
prefsList.stream().filter(key -> key.contains(EVAL_KEY)).forEach(key -> { for (String key : prefsList) {
if (!key.contains(EVAL_KEY)) {
continue;
}
if (key.startsWith("/")) { if (key.startsWith("/")) {
key = key.substring(1).replace('/', '.'); key = key.substring(1).replace('/', '.');
} }
list.add(new PreferenceRecord(key)); list.add(new PreferenceRecord(key));
}); }
} catch (Exception e) { } catch (Exception e) {
NotificationHelper.showError(null, "List eval preferences failed!"); NotificationHelper.showError(null, "List eval preferences failed!");
} }
@ -103,7 +126,9 @@ public class Resetter {
} }
public static void reset(List<EvalRecord> records) { public static void reset(List<EvalRecord> records) {
records.forEach(Resetter::reset); for (EvalRecord record : records) {
Resetter.reset(record);
}
} }
public static void reset(EvalRecord record) { public static void reset(EvalRecord record) {

View File

@ -5,22 +5,26 @@ import com.intellij.ide.Prefs;
import com.intellij.notification.Notification; import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType; import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.application.ApplicationActivationListener;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.openapi.wm.IdeFrame;
import com.intellij.util.messages.MessageBusConnection;
import io.zhile.research.intellij.ier.action.ResetAction;
import io.zhile.research.intellij.ier.action.RestartAction; import io.zhile.research.intellij.ier.action.RestartAction;
import io.zhile.research.intellij.ier.common.Resetter; import io.zhile.research.intellij.ier.common.Resetter;
import io.zhile.research.intellij.ier.helper.*; import io.zhile.research.intellij.ier.helper.Constants;
import io.zhile.research.intellij.ier.helper.DateTime;
import io.zhile.research.intellij.ier.helper.NotificationHelper;
import io.zhile.research.intellij.ier.helper.PluginHelper;
import io.zhile.research.intellij.ier.listener.AppEventListener; import io.zhile.research.intellij.ier.listener.AppEventListener;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class ResetTimer { public class ResetTimer {
private static final long RESET_PERIOD = 2160000000L; // 25 days private static final long RESET_PERIOD = 2160000000L; // 25 days
private static final String RESET_KEY = Constants.PLUGIN_PREFS_PREFIX + "." + Constants.IDE_NAME_LOWER + "." + Constants.IDE_HASH; private static final String RESET_KEY = Constants.PLUGIN_PREFS_PREFIX + "." + Constants.IDE_NAME_LOWER + "." + Constants.IDE_HASH;
private static ScheduledFuture<?> scheduledFuture; private static MessageBusConnection connection;
public static long getLastResetTime() { public static long getLastResetTime() {
return Prefs.getLong(RESET_KEY, 0L); return Prefs.getLong(RESET_KEY, 0L);
@ -37,39 +41,56 @@ public class ResetTimer {
return lastResetTime > 0 ? DateTime.getStringFromTimestamp(lastResetTime) : "Not yet"; return lastResetTime > 0 ? DateTime.getStringFromTimestamp(lastResetTime) : "Not yet";
} }
public synchronized static void start(final WeakReference<AnAction> weakResetAction) { public synchronized static void start(final WeakReference<ResetAction> weakResetAction) {
if (scheduledFuture != null) { if (connection != null) {
return; return;
} }
ApplicationManager.getApplication().getMessageBus().connect().subscribe(AppLifecycleListener.TOPIC, new AppEventListener()); ApplicationManager.getApplication().getMessageBus().connect().subscribe(AppLifecycleListener.TOPIC, new AppEventListener());
scheduledFuture = AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(() -> {
if (System.currentTimeMillis() - getLastResetTime() <= RESET_PERIOD) { connection = ApplicationManager.getApplication().getMessageBus().connect();
return; connection.subscribe(ApplicationActivationListener.TOPIC, new ApplicationActivationListener() {
public void applicationActivated(IdeFrame ideFrame) {
if (System.currentTimeMillis() - getLastResetTime() <= RESET_PERIOD) {
return;
}
stop();
AnAction resetAction = weakResetAction.get();
if (resetAction == null) {
return;
}
AnAction action = resetAction;
NotificationType type = NotificationType.INFORMATION;
String message = "It has been a long time since the last reset!\nWould you like to reset it again?";
if (Resetter.isAutoReset()) {
action = new RestartAction();
type = NotificationType.WARNING;
}
Notification notification = NotificationHelper.NOTIFICATION_GROUP.createNotification(PluginHelper.getPluginName(), null, message, type);
notification.addAction(action);
notification.notify(null);
} }
stop(); public void applicationDeactivated(IdeFrame ideFrame) {
applicationActivated(ideFrame);
AnAction resetAction = weakResetAction.get();
if (resetAction == null) {
return;
} }
AnAction action = Resetter.isAutoReset() ? new RestartAction() : resetAction; public void delayedApplicationDeactivated(IdeFrame ideFrame) {
String message = "It has been a long time since the last reset!\nWould you like to reset it again?";
Notification notification = NotificationHelper.NOTIFICATION_GROUP.createNotification(PluginHelper.getPluginName(), null, message, NotificationType.INFORMATION);
notification.addAction(action);
notification.notify(ProjectHelper.getCurrentProject()); }
}, 3, 600, TimeUnit.SECONDS); });
} }
public synchronized static void stop() { public synchronized static void stop() {
if (scheduledFuture == null || scheduledFuture.isCancelled()) { if (connection == null) {
return; return;
} }
scheduledFuture.cancel(false); connection.disconnect();
scheduledFuture = null; connection = null;
} }
} }

View File

@ -11,8 +11,10 @@ public class CustomRepository {
public static void checkAndAdd(@NotNull String host) { public static void checkAndAdd(@NotNull String host) {
List<String> hosts = UpdateSettings.getInstance().getStoredPluginHosts(); List<String> hosts = UpdateSettings.getInstance().getStoredPluginHosts();
if (hosts.stream().anyMatch(s -> s.equalsIgnoreCase(host))) { for (String s : hosts) {
return; if (s.equalsIgnoreCase(host)) {
return;
}
} }
hosts.add(host); hosts.add(host);

View File

@ -1,29 +0,0 @@
package io.zhile.research.intellij.ier.helper;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
public class ProjectHelper {
public static Project getCurrentProject() {
if (ProjectManager.getInstance().getOpenProjects().length == 0) {
return null;
}
DataContext dataContext = DataManager.getInstance().getDataContextFromFocus().getResultSync();
return CommonDataKeys.PROJECT.getData(dataContext);
}
public static Project getProject(AnActionEvent e) {
Project project = e.getProject();
if (project == null) {
return getCurrentProject();
}
return project;
}
}

View File

@ -3,12 +3,8 @@ package io.zhile.research.intellij.ier.listener;
import com.intellij.ide.plugins.DynamicPluginListener; import com.intellij.ide.plugins.DynamicPluginListener;
import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindowManager;
import io.zhile.research.intellij.ier.component.ResetTimer;
import io.zhile.research.intellij.ier.helper.Constants;
import io.zhile.research.intellij.ier.helper.NotificationHelper; import io.zhile.research.intellij.ier.helper.NotificationHelper;
import io.zhile.research.intellij.ier.helper.ProjectHelper; import io.zhile.research.intellij.ier.tw.MainToolWindowFactory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class PluginListener implements DynamicPluginListener { public class PluginListener implements DynamicPluginListener {
@ -21,13 +17,6 @@ public class PluginListener implements DynamicPluginListener {
@Override @Override
public void beforePluginUnload(@NotNull IdeaPluginDescriptor pluginDescriptor, boolean isUpdate) { public void beforePluginUnload(@NotNull IdeaPluginDescriptor pluginDescriptor, boolean isUpdate) {
ResetTimer.stop(); MainToolWindowFactory.unregisterAll();
Project project = ProjectHelper.getCurrentProject();
if (project == null) {
return;
}
ToolWindowManager.getInstance(project).unregisterToolWindow(Constants.ACTION_NAME);
} }
} }

View File

@ -2,10 +2,13 @@ package io.zhile.research.intellij.ier.tw;
import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory; import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.ui.content.Content; import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory; import com.intellij.ui.content.ContentFactory;
import io.zhile.research.intellij.ier.helper.Constants;
import io.zhile.research.intellij.ier.ui.form.MainForm; import io.zhile.research.intellij.ier.ui.form.MainForm;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -16,4 +19,10 @@ public class MainToolWindowFactory implements ToolWindowFactory, DumbAware {
Content content = ContentFactory.SERVICE.getInstance().createContent(mainForm.getContent(), "", true); Content content = ContentFactory.SERVICE.getInstance().createContent(mainForm.getContent(), "", true);
toolWindow.getContentManager().addContent(content); toolWindow.getContentManager().addContent(content);
} }
public static void unregisterAll() {
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
ToolWindowManager.getInstance(project).unregisterToolWindow(Constants.ACTION_NAME);
}
}
} }

View File

@ -84,7 +84,9 @@ public class MainForm {
listModel.clear(); listModel.clear();
List<EvalRecord> recordItemList = Resetter.getEvalRecords(); List<EvalRecord> recordItemList = Resetter.getEvalRecords();
recordItemList.forEach(record -> listModel.addElement(record.toString())); for (EvalRecord record : recordItemList) {
listModel.addElement(record.toString());
}
} }
private void resetEvalItems() { private void resetEvalItems() {
@ -101,7 +103,12 @@ public class MainForm {
} }
AppEventListener.disable(); AppEventListener.disable();
ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().restart()); ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().restart();
}
});
} }
private static void boldFont(Component component) { private static void boldFont(Component component) {