导读:本期聚焦于小伙伴创作的《如何在 Go 中测量通过 os/exec 启动的外部进程内存使用量》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何在 Go 中测量通过 os/exec 启动的外部进程内存使用量》有用,将其分享出去将是对创作者最好的鼓励。

在Go开发中,通过os/exec启动外部进程是常见操作,要测量这些进程的内存使用量,需要结合操作系统的进程管理接口实现,不同系统的实现方式存在差异。

如何在 Go 中测量通过 os/exec 启动的外部进程内存使用量

核心实现思路

os/exec启动外部进程后会返回*exec.Cmd对象,我们可以通过该对象的Process字段获取进程ID,再基于进程ID调用系统接口查询内存信息。Linux系统可以通过读取/proc文件系统获取进程内存数据,Windows系统可以调用系统API获取进程内存统计信息。

Linux系统下的实现

Linux系统中每个进程都会在/proc目录下对应一个以进程ID命名的文件夹,其中的status文件包含了进程的内存使用信息,我们只需要读取该文件并解析对应字段即可。

实现步骤

  • 通过cmd.Process.Pid获取外部进程的ID
  • 拼接/proc/[pid]/status文件路径
  • 读取文件内容,找到VmRSS字段,该字段表示进程实际使用的物理内存大小

代码示例

package main

import (
	"fmt"
	"io/ioutil"
	"os/exec"
	"strings"
)

// 获取Linux下进程的物理内存使用量,单位KB
func getLinuxProcessMemory(pid int) (int, error) {
	path := fmt.Sprintf("/proc/%d/status", pid)
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return 0, err
	}
	lines := strings.Split(string(content), "n")
	for _, line := range lines {
		if strings.HasPrefix(line, "VmRSS:") {
			// 格式为 VmRSS:   12345 kB
			fields := strings.Fields(line)
			if len(fields) >= 2 {
				var mem int
				fmt.Sscanf(fields[1], "%d", &mem)
				return mem, nil
			}
		}
	}
	return 0, fmt.Errorf("未找到VmRSS字段")
}

func main() {
	// 启动一个外部进程,这里以sleep命令为例
	cmd := exec.Command("sleep", "100")
	err := cmd.Start()
	if err != nil {
		fmt.Println("启动进程失败:", err)
		return
	}
	defer cmd.Process.Kill()

	// 获取进程内存使用量
	mem, err := getLinuxProcessMemory(cmd.Process.Pid)
	if err != nil {
		fmt.Println("获取内存失败:", err)
		return
	}
	fmt.Printf("外部进程PID: %d, 物理内存使用量: %d KBn", cmd.Process.Pid, mem)
}

Windows系统下的实现

Windows系统没有/proc文件系统,需要调用kernel32.dll中的GetProcessMemoryInfo函数来获取进程内存信息,Go中可以通过syscall包调用系统API实现。

代码示例

package main

import (
	"fmt"
	"os/exec"
	"syscall"
	"unsafe"
)

// 定义Windows内存信息结构体
type processMemoryCounters struct {
	Cb                         uint32
	PageFaultCount             uint32
	PeakWorkingSetSize         uint64
	WorkingSetSize             uint64
	QuotaPeakPagedPoolUsage    uint64
	QuotaPagedPoolUsage        uint64
	QuotaPeakNonPagedPoolUsage uint64
	QuotaNonPagedPoolUsage     uint64
	PagefileUsage              uint64
	PeakPagefileUsage          uint64
}

// 获取Windows下进程的物理内存使用量,单位字节
func getWindowsProcessMemory(pid int) (uint64, error) {
	// 打开进程获取句柄
	handle, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION|syscall.PROCESS_VM_READ, false, uint32(pid))
	if err != nil {
		return 0, err
	}
	defer syscall.CloseHandle(handle)

	// 加载kernel32.dll
	kernel32 := syscall.NewLazyDLL("kernel32.dll")
	getProcessMemoryInfo := kernel32.NewProc("GetProcessMemoryInfo")

	var memCounters processMemoryCounters
	memCounters.Cb = uint32(unsafe.Sizeof(memCounters))

	// 调用API获取内存信息
	ret, _, err := getProcessMemoryInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&memCounters)), uintptr(memCounters.Cb))
	if ret == 0 {
		return 0, err
	}
	// WorkingSetSize为工作集大小,即实际物理内存使用量
	return memCounters.WorkingSetSize, nil
}

func main() {
	// 启动一个外部进程,这里以notepad为例
	cmd := exec.Command("notepad.exe")
	err := cmd.Start()
	if err != nil {
		fmt.Println("启动进程失败:", err)
		return
	}
	defer cmd.Process.Kill()

	mem, err := getWindowsProcessMemory(cmd.Process.Pid)
	if err != nil {
		fmt.Println("获取内存失败:", err)
		return
	}
	fmt.Printf("外部进程PID: %d, 物理内存使用量: %d 字节n", cmd.Process.Pid, mem)
}

注意事项

  • 进程启动后需要等待一小段时间再获取内存信息,避免进程还未完成初始化导致数据不准确
  • 不同系统的内存单位不同,Linux下VmRSS默认单位是KB,Windows下WorkingSetSize默认单位是字节,使用时需要做统一转换
  • 如果外部进程已经退出,获取进程信息会返回错误,需要做好异常处理
  • 测量内存时建议多次采样取平均值,减少瞬时波动带来的误差

跨平台兼容方案

如果需要在不同系统下运行,可以通过runtime.GOOS判断当前系统类型,分别调用对应的实现方法:

package main

import (
	"fmt"
	"os/exec"
	"runtime"
)

func getProcessMemory(pid int) (uint64, error) {
	switch runtime.GOOS {
	case "linux":
		memKB, err := getLinuxProcessMemory(pid)
		if err != nil {
			return 0, err
		}
		// 转换为字节
		return uint64(memKB) * 1024, nil
	case "windows":
		return getWindowsProcessMemory(pid)
	default:
		return 0, fmt.Errorf("不支持的操作系统: %s", runtime.GOOS)
	}
}

func main() {
	cmd := exec.Command("sleep", "100")
	err := cmd.Start()
	if err != nil {
		fmt.Println("启动进程失败:", err)
		return
	}
	defer cmd.Process.Kill()

	mem, err := getProcessMemory(cmd.Process.Pid)
	if err != nil {
		fmt.Println("获取内存失败:", err)
		return
	}
	fmt.Printf("外部进程内存使用量: %d 字节n", mem)
}

Goos_exec进程内存测量runtime修改时间:2026-07-22 06:30:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。