Skip to content

Commit 224e048

Browse files
authored
Merge pull request #2243 from digma-ai/fix-memory-leak
Fix memory leak
2 parents b1c0f5e + febacd1 commit 224e048

File tree

19 files changed

+200
-192
lines changed

19 files changed

+200
-192
lines changed

ide-common/src/main/kotlin/org/digma/intellij/plugin/common/ProjectUtils.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ fun findActiveProject(): Project? {
2323
}
2424

2525

26-
fun isProjectValid(project: Project): Boolean {
27-
return !project.isDisposed && !project.isDefault && project.isOpen
26+
fun isProjectValid(project: Project?): Boolean {
27+
return project != null && !project.isDisposed && !project.isDefault && project.isOpen
2828
}

ide-common/src/main/kotlin/org/digma/intellij/plugin/posthog/PerformanceMetricsPosthogEventStartupActivity.kt

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import kotlinx.coroutines.launch
1414
import org.digma.intellij.plugin.analytics.AnalyticsService
1515
import org.digma.intellij.plugin.analytics.AnalyticsServiceException
1616
import org.digma.intellij.plugin.common.Retries
17+
import org.digma.intellij.plugin.common.findActiveProject
18+
import org.digma.intellij.plugin.common.isProjectValid
1719
import org.digma.intellij.plugin.errorreporting.ErrorReporter
1820
import org.digma.intellij.plugin.log.Log
1921
import org.digma.intellij.plugin.model.rest.version.PerformanceMetricsResponse
@@ -25,7 +27,7 @@ import kotlin.time.Duration.Companion.minutes
2527

2628
class PerformanceMetricsPosthogEventStartupActivity : StartupActivity {
2729
override fun runActivity(project: Project) {
28-
service<ContinuousPerformanceMetricsReporter>().start(project)
30+
service<ContinuousPerformanceMetricsReporter>().start()
2931
}
3032
}
3133

@@ -42,10 +44,10 @@ class ContinuousPerformanceMetricsReporter : Disposable {
4244
}
4345

4446

45-
fun start(project: Project) {
47+
fun start() {
4648

4749
if (started.getAndSet(true)) {
48-
Log.log(logger::info, "ContinuousPerformanceMetricsReporter.start called for project {} but already started", project.name)
50+
Log.log(logger::info, "ContinuousPerformanceMetricsReporter.start called for project {} but already started")
4951
return
5052
}
5153

@@ -55,38 +57,47 @@ class ContinuousPerformanceMetricsReporter : Disposable {
5557
@Suppress("UnstableApiUsage")
5658
disposingScope().launch {
5759

58-
if (!PersistenceService.getInstance().isFirstTimePerformanceMetrics()) {
59-
waitForFirstTime(this, project)
60-
//after first time wait 6 hours for next report
61-
launchContinuousReport(6.hours, project)
62-
} else {
63-
//this will happen on startup, make sure we have a report in 10 minutes and then every 6 hours
64-
launchContinuousReport(10.minutes, project)
60+
delay(2.minutes.inWholeMilliseconds)
61+
62+
if (isActive) {
63+
if (!PersistenceService.getInstance().isFirstTimePerformanceMetrics()) {
64+
waitForFirstTime(this)
65+
if (isActive) {
66+
//after first time wait 6 hours for next report
67+
launchContinuousReport(6.hours)
68+
}
69+
} else {
70+
//this will happen on startup, make sure we have a report in 10 minutes and then every 6 hours
71+
launchContinuousReport(10.minutes)
72+
}
6573
}
6674
}
6775

6876
}
6977

7078

71-
private suspend fun waitForFirstTime(coroutineScope: CoroutineScope, project: Project) {
79+
private suspend fun waitForFirstTime(coroutineScope: CoroutineScope) {
7280

7381
while (!PersistenceService.getInstance().isFirstTimePerformanceMetrics() && coroutineScope.isActive) {
7482
try {
7583

7684
delay(10.minutes.inWholeMilliseconds)
7785

78-
getAnalyticsService(project).let { analyticsService ->
79-
val result: PerformanceMetricsResponse = Retries.retryWithResult({
80-
analyticsService.performanceMetrics
81-
}, AnalyticsServiceException::class.java, 30000, 20)
82-
83-
if (result.metrics.isNotEmpty()) {
84-
filterMetrics(result)
85-
getActivityMonitor(project).let { activityMonitor ->
86-
Log.log(logger::info, "registering first time performance metrics")
87-
activityMonitor.registerPerformanceMetrics(result, true)
88-
if (!PersistenceService.getInstance().isFirstTimePerformanceMetrics()) {
89-
PersistenceService.getInstance().setFirstTimePerformanceMetrics()
86+
findActiveProject()?.takeIf { isProjectValid(it) }?.let { project ->
87+
88+
getAnalyticsService(project).let { analyticsService ->
89+
val result: PerformanceMetricsResponse = Retries.retryWithResult({
90+
analyticsService.performanceMetrics
91+
}, AnalyticsServiceException::class.java, 30000, 20)
92+
93+
if (result.metrics.isNotEmpty()) {
94+
filterMetrics(result)
95+
getActivityMonitor(project).let { activityMonitor ->
96+
Log.log(logger::info, "registering first time performance metrics")
97+
activityMonitor.registerPerformanceMetrics(result, true)
98+
if (!PersistenceService.getInstance().isFirstTimePerformanceMetrics()) {
99+
PersistenceService.getInstance().setFirstTimePerformanceMetrics()
100+
}
90101
}
91102
}
92103
}
@@ -95,13 +106,13 @@ class ContinuousPerformanceMetricsReporter : Disposable {
95106
} catch (e: Exception) {
96107
Log.warnWithException(logger, e, "failed in first time registerPerformanceMetrics")
97108
ErrorReporter.getInstance()
98-
.reportError(project, "PerformanceMetricsPosthogEventStartupActivity.firstTimePerformanceMetrics", e)
109+
.reportError("PerformanceMetricsPosthogEventStartupActivity.firstTimePerformanceMetrics", e)
99110
}
100111
}
101112
}
102113

103114

104-
private fun launchContinuousReport(nextReport: Duration, project: Project) {
115+
private fun launchContinuousReport(nextReport: Duration) {
105116

106117
@Suppress("UnstableApiUsage")
107118
disposingScope().launch {
@@ -110,18 +121,24 @@ class ContinuousPerformanceMetricsReporter : Disposable {
110121

111122
while (isActive) {
112123
try {
113-
getAnalyticsService(project).let { analyticsService ->
114-
val result: PerformanceMetricsResponse = Retries.retryWithResult({
115-
analyticsService.performanceMetrics
116-
}, AnalyticsServiceException::class.java, 30000, 20)
117124

118-
if (result.metrics.isNotEmpty()) {
119-
filterMetrics(result)
120-
Log.log(logger::info, "registering continuous performance metrics")
121-
getActivityMonitor(project).registerPerformanceMetrics(result, false)
125+
findActiveProject()?.takeIf { isProjectValid(it) }?.let { project ->
126+
127+
getAnalyticsService(project).let { analyticsService ->
128+
val result: PerformanceMetricsResponse = Retries.retryWithResult({
129+
analyticsService.performanceMetrics
130+
}, AnalyticsServiceException::class.java, 30000, 20)
131+
132+
if (result.metrics.isNotEmpty()) {
133+
filterMetrics(result)
134+
Log.log(logger::info, "registering continuous performance metrics")
135+
getActivityMonitor(project).registerPerformanceMetrics(result, false)
136+
}
122137
}
138+
123139
}
124140

141+
125142
delay(6.hours.inWholeMilliseconds)
126143

127144
} catch (e: Exception) {

src/main/java/org/digma/intellij/plugin/documentation/DocumentationFileEditor.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class DocumentationFileEditor extends UserDataHolderBase implements FileE
1616
private final VirtualFile file;
1717

1818
@Nullable
19-
private final JCefComponent jCefComponent;
19+
private JCefComponent jCefComponent;
2020

2121

2222
public DocumentationFileEditor(Project project, DocumentationVirtualFile file) {
@@ -28,10 +28,10 @@ public DocumentationFileEditor(Project project, DocumentationVirtualFile file) {
2828
private JCefComponent createJcefComponent(Project project, DocumentationVirtualFile file) {
2929

3030
if (JBCefApp.isSupported()) {
31-
return new JCefComponent.JCefComponentBuilder(project, "Documentation", DocumentationService.getInstance(project))
32-
.url(DocumentationConstants.DOCUMENTATION_URL)
33-
.addMessageRouterHandler(new DocumentationMessageRouterHandler(project))
34-
.schemeHandlerFactory(new DocumentationSchemeHandlerFactory(project, file))
31+
return new JCefComponent.JCefComponentBuilder(project, "Documentation", DocumentationService.getInstance(project),
32+
DocumentationConstants.DOCUMENTATION_URL,
33+
new DocumentationMessageRouterHandler(project),
34+
new DocumentationSchemeHandlerFactory(project, file))
3535
.withDownloadAdapter(new DownloadHandlerAdapter())
3636
.build();
3737

@@ -99,6 +99,7 @@ public void removePropertyChangeListener(@NotNull PropertyChangeListener listene
9999
public void dispose() {
100100
if (jCefComponent != null) {
101101
jCefComponent.dispose();
102+
jCefComponent = null;
102103
}
103104
}
104105

src/main/java/org/digma/intellij/plugin/jaegerui/JaegerUIFileEditor.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class JaegerUIFileEditor extends UserDataHolderBase implements FileEditor
1616
private final VirtualFile file;
1717

1818
@Nullable
19-
private final JCefComponent jCefComponent;
19+
private JCefComponent jCefComponent;
2020

2121
public JaegerUIFileEditor(Project project, JaegerUIVirtualFile file) {
2222
this.file = file;
@@ -27,10 +27,10 @@ public JaegerUIFileEditor(Project project, JaegerUIVirtualFile file) {
2727
private JCefComponent createJcefComponent(Project project, JaegerUIVirtualFile file) {
2828

2929
if (JBCefApp.isSupported()) {
30-
return new JCefComponent.JCefComponentBuilder(project, "JaegerUI", JaegerUIService.getInstance(project))
31-
.url(JaegerUIConstants.JAEGER_UI_URL)
32-
.addMessageRouterHandler(new JaegerUIMessageRouterHandler(project))
33-
.schemeHandlerFactory(new JaegerUiSchemeHandlerFactory(project, file))
30+
return new JCefComponent.JCefComponentBuilder(project, "JaegerUI", this,
31+
JaegerUIConstants.JAEGER_UI_URL,
32+
new JaegerUIMessageRouterHandler(project),
33+
new JaegerUiSchemeHandlerFactory(project, file))
3434
.withDownloadAdapter(new DownloadHandlerAdapter())
3535
.build();
3636

@@ -98,6 +98,7 @@ public void removePropertyChangeListener(@NotNull PropertyChangeListener listene
9898
public void dispose() {
9999
if (jCefComponent != null) {
100100
jCefComponent.dispose();
101+
jCefComponent = null;
101102
}
102103
}
103104

src/main/java/org/digma/intellij/plugin/toolwindow/DigmaSidePaneToolWindowFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.intellij.openapi.Disposable;
44
import com.intellij.openapi.diagnostic.Logger;
55
import com.intellij.openapi.project.Project;
6+
import com.intellij.openapi.util.Disposer;
67
import com.intellij.openapi.wm.*;
78
import com.intellij.ui.content.ContentFactory;
89
import com.intellij.util.ui.JBUI;
@@ -76,6 +77,9 @@ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindo
7677
//mainContent contains the mainCardsPanel ,MainToolWindowCardsController switches between no connection and mainToolWindowPanel
7778
var mainContent = ContentFactory.getInstance().createContent(mainCardsPanel, null, false);
7879

80+
//register disposable for mainContent,any project service is good for parent disposable
81+
Disposer.register(AnalyticsService.getInstance(project), mainContent);
82+
7983
toolWindow.getContentManager().addContent(mainContent);
8084

8185

src/main/kotlin/org/digma/intellij/plugin/ui/insights/InsightsService.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ class InsightsService(val project: Project) : InsightsServiceImpl(project) {
4444
}
4545
}
4646

47+
override fun dispose(){
48+
jCefComponent = null
49+
}
50+
4751
fun setJCefComponent(jCefComponent: JCefComponent?) {
4852
this.jCefComponent = jCefComponent
4953
}

0 commit comments

Comments
 (0)