如何读取 Windows 内存使用情况?

问题描述 投票:0回答:1

我有一个用Go在Windows上运行的数据转发应用程序。 它有一个使用 gotk3/gtk3 的 GUI 前端。 在正常情况下,Windows 报告该程序使用大约 25MB RAM。

GUI 显示每 2 秒更新一次的通道统计信息,我仅在 GUI 具有顶级焦点时更新这些统计信息。 我可能会尝试增加更新间隔作为开始。

当更新运行时,内存使用缓慢但不可避免地增加,直到程序在一个小时左右崩溃,但这似乎是 Go memstats 之外的内存。 memstats 报告的数字变化不大,所以肯定是 gtk3 使用了内存,而 Windows 没有收回。

一旦程序失去焦点并且统计数据更新停止,内存使用量就会停止增长,但 Windows 在另外 7 或 8 分钟内不会恢复内存使用量,此时内存使用量开始稳定下降到应有的水平。

我不知道如何停止内存蠕变,我的猜测是 gtk3 的 Gotk3 包装释放内存的速度并没有像它用完内存的那么快。

我的问题是我可以监控 Windows 在 Go 中分配给程序的内容,然后我可以暂停统计数据更新,直到内存使用量再次下降吗?

我找不到可以提供该信息的包,因为我说 Go 运行时都没有。Memstats 似乎与 Windows 所说的相符。

添加代码是因为 a) 每个人都喜欢一些代码,b) 有人可能知道如何阻止 gotk3 耗尽内存。

func updateStats() {
    MainListStore.ForEach(func(tmodel *gtk.TreeModel, path *gtk.TreePath, iterfe *gtk.TreeIter) bool {
        // get the channel no
        value, _ := tmodel.GetValue(iterfe, MCOL_INPORT)
        goValue, _ := value.GoValue()
        key := goValue.(int)
        // copy stats to liststore
        Mutex.Lock()
        err := MainListStore.Set(iterfe,
            []int{MCOL_STATPIX, MCOL_STATINT, MCOL_SPDIN, MCOL_SPDOUT},
            []interface{}{Pixes[Statmap[key][0]], Statmap[key][0], Statmap[key][1], Statmap[key][2]})
        Mutex.Unlock()
        if err != nil {
            Logit.Printf("Error: error updating stats chan %d, %v", key, err)
        }
        return false // keep iterating
    })
    return
}
windows go gtk3
1个回答
0
投票

通过

syscall
golang.org/x/sys

使用 Windows API

您可以使用

syscall
golang.org/x/sys/windows
包与 Windows API 进行交互。具体来说,
GlobalMemoryStatusEx
GetProcessMemoryInfo
API 可以为您提供系统级内存使用统计信息,包括私有字节和工作集大小(这是任务管理器通常报告的内容)。

我使用

GetProcessMemoryInfo
准备了一个示例:

  1. go get golang.org/x/sys/windows
  2. 使用
    GetProcessMemoryInfo
    API 获取内存使用情况。
package main

import (
    "fmt"
    "syscall"
    "unsafe"
    "golang.org/x/sys/windows"
)

var (
    psapi              = windows.NewLazySystemDLL("psapi.dll")
    procGetProcessMemoryInfo = psapi.NewProc("GetProcessMemoryInfo")
)

type PROCESS_MEMORY_COUNTERS struct {
    cb                         uint32
    PageFaultCount             uint32
    PeakWorkingSetSize         uintptr
    WorkingSetSize             uintptr
    QuotaPeakPagedPoolUsage    uintptr
    QuotaPagedPoolUsage        uintptr
    QuotaPeakNonPagedPoolUsage uintptr
    QuotaNonPagedPoolUsage     uintptr
    PagefileUsage              uintptr
    PeakPagefileUsage          uintptr
}

func GetProcessMemoryInfo(handle windows.Handle) (PROCESS_MEMORY_COUNTERS, error) {
    var memCounters PROCESS_MEMORY_COUNTERS
    memCounters.cb = uint32(unsafe.Sizeof(memCounters))
    r, _, err := procGetProcessMemoryInfo.Call(
        uintptr(handle),
        uintptr(unsafe.Pointer(&memCounters)),
        uintptr(memCounters.cb),
    )
    if r == 0 {
        return memCounters, err
    }
    return memCounters, nil
}

func main() {
    pid := windows.GetCurrentProcess() // Get current process handle
    memInfo, err := GetProcessMemoryInfo(pid)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Printf("Memory Usage:\n")
    fmt.Printf("Working Set Size: %v bytes\n", memInfo.WorkingSetSize) // actual physical memory used by application
    fmt.Printf("Pagefile Usage: %v bytes\n", memInfo.PagefileUsage) // virtual memory
}

这应该可以让您深入了解 Windows 报告的 Go 应用程序的内存使用情况,而不仅仅是 Go 堆。

注意:现在您可以使用它来根据内存使用情况监控和管理应用程序暂停或播放状态。

现在,如果即使停止更新后内存使用量仍然继续上升,则可能是gotk3管理内存的方式存在内存泄漏。

在这种情况下,我建议您在不再需要时手动释放表面、图像或列表等资源。 另请记住,GTK 对象需要适当的清理,而 Go 的垃圾收集器不会自动清理在 Go 外部分配的资源(如 GTK)。

© www.soinside.com 2019 - 2024. All rights reserved.