Search code examples
gofyne

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


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 = &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()

}

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 := <-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 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 > 50 {
        runtime.GC()
        cour = 1
        text.Set("")
    }

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.


Solution

  • 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.