Skip to content

Commit 5638dc5

Browse files
authored
Merge pull request #424 from NucleusFramework/feat/gc-on-popup-hide
feat(trayapp): trim the heap after the popup is hidden
2 parents f70af80 + 72a8811 commit 5638dc5

1 file changed

Lines changed: 26 additions & 0 deletions

File tree

  • src/jvmMain/kotlin/dev/nucleusframework/composenativetray/tray/api

src/jvmMain/kotlin/dev/nucleusframework/composenativetray/tray/api/TrayApp.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import kotlinx.coroutines.Dispatchers
6363
import kotlinx.coroutines.delay
6464
import kotlinx.coroutines.flow.first
6565
import kotlinx.coroutines.launch
66+
import kotlinx.coroutines.withContext
6667
import org.jetbrains.compose.resources.DrawableResource
6768
import org.jetbrains.compose.resources.painterResource
6869
import java.util.concurrent.atomic.AtomicLong
@@ -121,6 +122,29 @@ private val defaultVerticalOffset =
121122
}
122123
}
123124

125+
private const val GC_AFTER_HIDE_DELAY_MS = 1_500L
126+
127+
/**
128+
* Trims the heap after the popup leaves the screen. The popup keeps its
129+
* composition alive while hidden (so state survives hide/show), which means
130+
* garbage from the visible session otherwise lingers for as long as the app
131+
* idles in the tray — exactly the footprint users check in the task manager.
132+
* Right after the exit animation there is no UI on screen, so the collection
133+
* pause is invisible.
134+
*
135+
* Must be called from the visibility `LaunchedEffect`: reshowing the popup
136+
* restarts the effect and cancels the [delay], debouncing rapid toggles for
137+
* free. The collection runs off the UI thread so the tray loop only pays the
138+
* stop-the-world portion.
139+
*/
140+
private suspend fun requestGcWhileHidden() {
141+
delay(GC_AFTER_HIDE_DELAY_MS)
142+
withContext(Dispatchers.Default) {
143+
@Suppress("ExplicitGarbageCollectionCall")
144+
System.gc()
145+
}
146+
}
147+
124148
// --------------------- Public API (overloads) ---------------------
125149

126150
@Composable
@@ -661,6 +685,7 @@ private fun TrayAppImplPanel(
661685
snapshotFlow { visibleState.isIdle && !visibleState.currentState }.first { it }
662686
popupOnScreen = false
663687
lastHiddenAtMs.set(System.currentTimeMillis())
688+
requestGcWhileHidden()
664689
}
665690
}
666691
}
@@ -851,6 +876,7 @@ private fun NucleusApplicationScope.TrayAppImplWindow(
851876
snapshotFlow { visibleState.isIdle && !visibleState.currentState }.first { it }
852877
shouldShowWindow = false
853878
lastHiddenAtMs.set(System.currentTimeMillis())
879+
requestGcWhileHidden()
854880
}
855881
}
856882
}

0 commit comments

Comments
 (0)