My go fyne application is gradually increasing memory usage when the interface is refreshed in the foreground, how can I keep the memory stable?

huangapple go评论87阅读模式
英文:

My go fyne application is gradually increasing memory usage when the interface is refreshed in the foreground, how can I keep the memory stable?

问题

应用程序在运行过程中将日志内容输出到MultiLineEntry,并且当应用程序处于前台时,应用程序占用的内存会逐渐增加,但在后台可以保持稳定。我想知道问题出在哪里?

这是应用程序的主要功能:

var conf = &Conf{}

func main() {
	go http.ListenAndServe("0.0.0.0:6060", nil)
	a := app.New()
	a.Settings().SetTheme(&myTheme{})
	w := a.NewWindow("forward")

	tab := container.NewAppTabs(
		container.NewTabItem("data1", WeatherScreen()),
		container.NewTabItem("data2", TossScreen()),
		//container.NewTabItem("per", PreferenceScreen(w)),
		container.NewTabItem("about", widget.NewLabel("Version:1.0")),
	)
	//tab.SetTabLocation(container.TabLocationLeading)
	rootVBox := container.NewVBox(tab, CreateLogs())

	w.SetContent(rootVBox)

	w.Resize(fyne.NewSize(700, 364))
	w.SetMaster()
	w.SetFixedSize(true)
	resource, _ := fyne.LoadResourceFromPath("Graphicloads-Polygon-Next-2.ico")
	a.SetIcon(resource)
	if desk, ok := a.(desktop.App); ok {
		m := fyne.NewMenu("forward",
			fyne.NewMenuItem("show", func() {
				w.Show()
			},
			),
		)
		//desk.SetSystemTrayIcon(resource)
		desk.SetSystemTrayMenu(m)
	}
	w.SetIcon(resource)
	w.SetCloseIntercept(func() {
		//hide
		w.Hide()
	})
	w.CenterOnScreen()
	InitData()
	//longIp := float32(80)
	//shortPort := float32(50)
	conf = loadConfig()
	w.Show()
	a.Run()

}

这是我用来处理日志的函数:

var logFlag = make(chan string, 10)
var cour = 1
var text = binding.NewString()
func CreateLogs() fyne.CanvasObject {
	logs := widget.NewEntryWithData(text)
	logs.MultiLine = true
	logs.Validator = nil
	logs.Resize(fyne.NewSize(688, 230))
        //update text
	go updateLogs(logFlag, logs)
	contain := container.NewWithoutLayout(logs)
	return contain
}
func updateLogs(l chan string, logs *widget.Entry) {
	for {
		if d, ok := <-l; ok {
			t, _ := text.Get()
			text.Set(t + d)
			logs.CursorRow = cour
			runtime.GC()
		}
	}
}
func appendLogs(name string, format string, a ...any) {
	now := time.Now()
	year, month, day := now.Date()
	str := fmt.Sprintf(format, a...)

	y := strconv.Itoa(year)
	var m string
	if int(month) >= 10 {
		m = strconv.Itoa(int(month))
	} else {
		m = "0" + strconv.Itoa(int(month))
	}
	var d string
	if day >= 10 {
		d = strconv.Itoa(day)
	} else {
		d = "0" + strconv.Itoa(day)
	}

	dateHeader := y + "/" + m + "/" + d + " "

	hour, min, sec := now.Clock()
	var h string
	if hour >= 10 {
		h = strconv.Itoa(hour)
	} else {
		h = "0" + strconv.Itoa(hour)
	}
	var mi string
	if min >= 10 {
		mi = strconv.Itoa(min)
	} else {
		mi = "0" + strconv.Itoa(min)
	}
	var s string
	if sec >= 10 {
		s = strconv.Itoa(sec)
	} else {
		s = "0" + strconv.Itoa(sec)
	}
	timeHeader := h + ":" + mi + ":" + s + " "
	header := dateHeader + timeHeader + name + " "
	str = header + str + "\n"
	cour++
	if cour > 50 {
		runtime.GC()
		cour = 1
		text.Set("")
	}
	logFlag <- str

}

每次有日志要导出时,都会调用appendLogs函数。

我尝试限制日志条目的数量并清除绑定数据的内容,但这并没有停止内存增长。

if cour > 50 {
        runtime.GC()
        cour = 1
        text.Set("")
    }

我还尝试注释掉整个appendLogs函数,但这也没有解决问题。

我希望应用程序在前台时内存保持稳定。

英文:

The application will output the log content to MultiLineEntry during operation, and the memory occupied by the application will gradually increase when the application is in the foreground, but it can maintain a stable occupation in the background.I would like to know what the problem is?

This is the main function of the application

var conf = &amp;Conf{}
func main() {
go http.ListenAndServe(&quot;0.0.0.0:6060&quot;, nil)
a := app.New()
a.Settings().SetTheme(&amp;myTheme{})
w := a.NewWindow(&quot;forward&quot;)
tab := container.NewAppTabs(
container.NewTabItem(&quot;data1&quot;, WeatherScreen()),
container.NewTabItem(&quot;data2&quot;, TossScreen()),
//container.NewTabItem(&quot;per&quot;, PreferenceScreen(w)),
container.NewTabItem(&quot;about&quot;, widget.NewLabel(&quot;Version:1.0&quot;)),
)
//tab.SetTabLocation(container.TabLocationLeading)
rootVBox := container.NewVBox(tab, CreateLogs())
w.SetContent(rootVBox)
w.Resize(fyne.NewSize(700, 364))
w.SetMaster()
w.SetFixedSize(true)
resource, _ := fyne.LoadResourceFromPath(&quot;Graphicloads-Polygon-Next-2.ico&quot;)
a.SetIcon(resource)
if desk, ok := a.(desktop.App); ok {
m := fyne.NewMenu(&quot;forward&quot;,
fyne.NewMenuItem(&quot;show&quot;, func() {
w.Show()
},
),
)
//desk.SetSystemTrayIcon(resource)
desk.SetSystemTrayMenu(m)
}
w.SetIcon(resource)
w.SetCloseIntercept(func() {
//hide
w.Hide()
})
w.CenterOnScreen()
InitData()
//longIp := float32(80)
//shortPort := float32(50)
conf = loadConfig()
w.Show()
a.Run()
}

This is the function I use to process the logs

var logFlag = make(chan string, 10)
var cour = 1
var text = binding.NewString()
func CreateLogs() fyne.CanvasObject {
logs := widget.NewEntryWithData(text)
logs.MultiLine = true
logs.Validator = nil
logs.Resize(fyne.NewSize(688, 230))
//update text
go updateLogs(logFlag, logs)
contain := container.NewWithoutLayout(logs)
return contain
}
func updateLogs(l chan string, logs *widget.Entry) {
for {
if d, ok := &lt;-l; ok {
t, _ := text.Get()
text.Set(t + d)
logs.CursorRow = cour
runtime.GC()
}
}
}
func appendLogs(name string, format string, a ...any) {
now := time.Now()
year, month, day := now.Date()
str := fmt.Sprintf(format, a...)
y := strconv.Itoa(year)
var m string
if int(month) &gt;= 10 {
m = strconv.Itoa(int(month))
} else {
m = &quot;0&quot; + strconv.Itoa(int(month))
}
var d string
if day &gt;= 10 {
d = strconv.Itoa(day)
} else {
d = &quot;0&quot; + strconv.Itoa(day)
}
dateHeader := y + &quot;/&quot; + m + &quot;/&quot; + d + &quot; &quot;
hour, min, sec := now.Clock()
var h string
if hour &gt;= 10 {
h = strconv.Itoa(hour)
} else {
h = &quot;0&quot; + strconv.Itoa(hour)
}
var mi string
if min &gt;= 10 {
mi = strconv.Itoa(min)
} else {
mi = &quot;0&quot; + strconv.Itoa(min)
}
var s string
if sec &gt;= 10 {
s = strconv.Itoa(sec)
} else {
s = &quot;0&quot; + strconv.Itoa(sec)
}
timeHeader := h + &quot;:&quot; + mi + &quot;:&quot; + s + &quot; &quot;
header := dateHeader + timeHeader + name + &quot; &quot;
str = header + str + &quot;\n&quot;
cour++
if cour &gt; 50 {
runtime.GC()
cour = 1
text.Set(&quot;&quot;)
}
logFlag &lt;- str
}

appendLogs is called once every time there is a log to be exported.

I tried to limit the number of log entries and clear the content of the bound data, but this did not stop the memory growth.

if cour &gt; 50 {
runtime.GC()
cour = 1
text.Set(&quot;&quot;)
}

I also tried commenting out the entire appendLogs, but that didn't solve the problem either.

I want the memory to remain stable while the application is in the foreground.

答案1

得分: 0

将文本添加到“Entry”中会导致性能问题,因为它当前会渲染所有内容,而且“SetText”必须解析所有换行符以进行布局。

为了使处理大量数据的内容良好,您可以考虑使用每行一个“Label”的“List”,无需解析,也无需渲染屏幕外的项目。

未来版本的“Entry”旨在改善内存使用情况,但由于解析要求,单个“SetText”始终会随时间变慢。

英文:

Adding lines of text to an Entry will cause performance issues as it currently renders all the content, plus the SetText must parse all your newlines to lay it out.

To make something handling large data well you might consider List with a Label per line, no parsing and also no rendering of items off screen.

A future version of Entry aims to improve the memory usage, but a single SetText will always get slow over time due to the parsing requirement.

huangapple
  • 本文由 发表于 2023年2月22日 17:23:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75530554.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定