fix: memory leaks

This commit is contained in:
hstyi
2025-02-20 17:13:37 +08:00
committed by hstyi
parent 0000e4610a
commit 604e07b43a
3 changed files with 58 additions and 49 deletions

View File

@@ -0,0 +1,42 @@
package app.termora.terminal.panel.vw
import app.termora.Disposable
import kotlinx.coroutines.*
import org.slf4j.LoggerFactory
import javax.swing.JPanel
import kotlin.time.Duration.Companion.milliseconds
abstract class AutoRefreshPanel : JPanel(), Disposable {
companion object {
private val log = LoggerFactory.getLogger(AutoRefreshPanel::class.java)
}
protected val coroutineScope = CoroutineScope(Dispatchers.IO)
protected abstract suspend fun refresh(isFirst: Boolean)
init {
coroutineScope.launch {
var isFirst = true
while (coroutineScope.isActive) {
try {
refresh(isFirst)
isFirst = false
} catch (e: Exception) {
if (log.isErrorEnabled) {
log.error(e.message, e)
}
if (isFirst) {
break
}
} finally {
delay(1000.milliseconds)
}
}
}
}
override fun dispose() {
coroutineScope.cancel()
}
}

View File

@@ -1,14 +1,13 @@
package app.termora.terminal.panel.vw package app.termora.terminal.panel.vw
import app.termora.I18n import app.termora.*
import app.termora.Icons
import app.termora.SSHTerminalTab
import app.termora.SshClients
import com.formdev.flatlaf.extras.FlatSVGIcon import com.formdev.flatlaf.extras.FlatSVGIcon
import com.jgoodies.forms.builder.FormBuilder import com.jgoodies.forms.builder.FormBuilder
import com.jgoodies.forms.layout.FormLayout import com.jgoodies.forms.layout.FormLayout
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.jdesktop.swingx.JXBusyLabel import org.jdesktop.swingx.JXBusyLabel
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -22,7 +21,6 @@ import java.io.StringReader
import javax.swing.* import javax.swing.*
import javax.xml.parsers.DocumentBuilderFactory import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.XPathFactory import javax.xml.xpath.XPathFactory
import kotlin.time.Duration.Companion.milliseconds
class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindowManager) : class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindowManager) :
SSHVisualWindow(tab, "NVIDIA-SMI", visualWindowManager) { SSHVisualWindow(tab, "NVIDIA-SMI", visualWindowManager) {
@@ -79,6 +77,8 @@ class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWind
percentageBtn.icon = if (isPercentage) Icons.text else Icons.percentage percentageBtn.icon = if (isPercentage) Icons.text else Icons.percentage
nvidiaSMIPanel.refreshPanel() nvidiaSMIPanel.refreshPanel()
} }
Disposer.register(this, nvidiaSMIPanel)
} }
private data class GPU( private data class GPU(
@@ -183,8 +183,7 @@ class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWind
} }
} }
private inner class NvidiaSMIPanel : JPanel(BorderLayout()) { private inner class NvidiaSMIPanel : AutoRefreshPanel() {
private val coroutineScope = CoroutineScope(Dispatchers.IO)
private val xPath by lazy { XPathFactory.newInstance().newXPath() } private val xPath by lazy { XPathFactory.newInstance().newXPath() }
private val db by lazy { private val db by lazy {
@@ -224,6 +223,8 @@ class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWind
private fun initViews() { private fun initViews() {
layout = BorderLayout()
add( add(
FormBuilder.create().debug(false) FormBuilder.create().debug(false)
.layout( .layout(
@@ -253,27 +254,11 @@ class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWind
private fun initEvents() { private fun initEvents() {
coroutineScope.launch {
// 首次刷新
refresh(true)
while (coroutineScope.isActive) {
delay(1000.milliseconds)
try {
refresh()
} catch (e: Exception) {
if (log.isErrorEnabled) {
log.error(e.message, e)
}
}
}
}
} }
private suspend fun refresh(isFirst: Boolean = false) { override suspend fun refresh(isFirst: Boolean) {
val session = tab.getData(SSHTerminalTab.SSHSession) ?: return val session = tab.getData(SSHTerminalTab.SSHSession) ?: return
val doc = try { val doc = try {
@@ -347,7 +332,6 @@ class NvidiaSMIVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWind
refreshPanel() refreshPanel()
} }
} }
private fun initPanel() { private fun initPanel() {

View File

@@ -3,8 +3,9 @@ package app.termora.terminal.panel.vw
import app.termora.* import app.termora.*
import com.jgoodies.forms.builder.FormBuilder import com.jgoodies.forms.builder.FormBuilder
import com.jgoodies.forms.layout.FormLayout import com.jgoodies.forms.layout.FormLayout
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.apache.sshd.client.session.ClientSession import org.apache.sshd.client.session.ClientSession
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -12,7 +13,6 @@ import java.awt.BorderLayout
import javax.swing.* import javax.swing.*
import javax.swing.table.DefaultTableCellRenderer import javax.swing.table.DefaultTableCellRenderer
import javax.swing.table.DefaultTableModel import javax.swing.table.DefaultTableModel
import kotlin.time.Duration.Companion.milliseconds
class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindowManager) : class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: VisualWindowManager) :
@@ -40,9 +40,8 @@ class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: Vi
Disposer.register(this, systemInformationPanel) Disposer.register(this, systemInformationPanel)
} }
private inner class SystemInformationPanel : JPanel(BorderLayout()), Disposable { private inner class SystemInformationPanel : AutoRefreshPanel() {
private val coroutineScope = CoroutineScope(Dispatchers.IO)
private val cpuProgressBar = SmartProgressBar() private val cpuProgressBar = SmartProgressBar()
private val memoryProgressBar = SmartProgressBar() private val memoryProgressBar = SmartProgressBar()
@@ -63,6 +62,7 @@ class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: Vi
private fun initViews() { private fun initViews() {
layout = BorderLayout()
add(createPanel(), BorderLayout.CENTER) add(createPanel(), BorderLayout.CENTER)
} }
@@ -109,22 +109,10 @@ class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: Vi
} }
private fun initEvents() { private fun initEvents() {
coroutineScope.launch {
while (coroutineScope.isActive) {
try {
refresh()
} catch (e: Exception) {
if (log.isErrorEnabled) {
log.error(e.message, e)
}
} finally {
delay(1000.milliseconds)
}
}
}
} }
private suspend fun refresh() { override suspend fun refresh(isFirst: Boolean) {
val session = tab.getData(SSHTerminalTab.SSHSession) ?: return val session = tab.getData(SSHTerminalTab.SSHSession) ?: return
try { try {
@@ -144,7 +132,6 @@ class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: Vi
log.error("refreshDisk", e) log.error("refreshDisk", e)
} }
} }
} }
private suspend fun refreshCPUAndMem(session: ClientSession) { private suspend fun refreshCPUAndMem(session: ClientSession) {
@@ -290,10 +277,6 @@ class SystemInformationVisualWindow(tab: SSHTerminalTab, visualWindowManager: Vi
} }
} }
override fun dispose() {
coroutineScope.cancel()
}
} }
private data class Mem( private data class Mem(