You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift实现列出带参数进程遇问题,求排查及内存分配指导

Swift 进程枚举代码错误分析与修正

一、内存分配的正确方式

原代码中info = malloc(length)本身合法,但存在类型安全隐患,更推荐Swift风格的类型化内存分配:

  • 先通过length / MemoryLayout<kinfo_proc>.stride计算进程结构体的数量(用stride而非size,适配结构体内存对齐规则)
  • 使用UnsafeMutablePointer<kinfo_proc>.allocate(capacity: count)分配类型化内存,避免裸指针转换风险
  • 用defer语句确保内存自动释放,替代手动free

示例代码:

let count = length / MemoryLayout<kinfo_proc>.stride
let info = UnsafeMutablePointer<kinfo_proc>.allocate(capacity: count)
defer { info.deallocate() }

二、print输出错误的核心原因

KERN_PROCARGS2返回的缓冲区并非直接以进程名称开头,其格式为:

  1. 首段是int类型的参数个数(argc)
  2. 后续才是以null结尾的进程路径/名称字符串(argv[0])

原代码直接读取缓冲区开头,会把参数个数当作字符串输出,正确做法是跳过argc字段后读取进程名称:

if sysctl(&mib, 3, buffer, &maxArgumentsSize, nil, 0) == 0 {
    // 跳过argc字段
    var offset = MemoryLayout<Int32>.stride
    // 跳过空字符,定位到argv[0]起始位置
    while offset < Int(maxArgumentsSize) && buffer[offset] == 0 {
        offset += 1
    }
    let processName = String(cString: buffer + offset, encoding: .utf8)
    print(processName ?? "未知进程")
}

三、其他关键错误修正

  • 循环越界:原代码for index in 0...count会访问超出数组范围的元素,应改为0..<count
  • 内存释放错误:UnsafeMutablePointer.allocate分配的内存需用deallocate()释放,而非C的free()函数
  • ARGMAX类型不匹配:KERN_ARGMAX返回的是Int32类型,原代码用MemoryLayout<Int>.size作为size参数会导致64位系统下的长度错误,应改为MemoryLayout<Int32>.size

修正后的完整代码

import Darwin

var maxArgumentsSize: Int32 = 0
var size: size_t = MemoryLayout<Int32>.size
let argmaxMib: [Int32] = [CTL_KERN, KERN_ARGMAX]
if sysctl(argmaxMib, 2, &maxArgumentsSize, &size, nil, 0) == -1 {
    maxArgumentsSize = 4096
}

let procMib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_ALL]
var length: size_t = 0

// 获取进程列表所需内存长度
if sysctl(procMib, 3, nil, &length, nil, 0) < 0 {
    exit(EXIT_FAILURE)
}

// 分配类型化内存存储进程信息
let count = length / MemoryLayout<kinfo_proc>.stride
let info = UnsafeMutablePointer<kinfo_proc>.allocate(capacity: count)
defer { info.deallocate() }

// 读取进程列表
if sysctl(procMib, 3, info, &length, nil, 0) < 0 {
    exit(EXIT_FAILURE)
}

// 遍历输出每个进程信息
for index in 0..<count {
    let pid = info[index].kp_proc.p_pid
    let buffer = UnsafeMutablePointer<CChar>.allocate(capacity: Int(maxArgumentsSize))
    defer { buffer.deallocate() }
    
    let argsMib: [Int32] = [CTL_KERN, KERN_PROCARGS2, pid]
    var bufferSize = maxArgumentsSize
    if sysctl(argsMib, 3, buffer, &bufferSize, nil, 0) == 0 {
        var offset = MemoryLayout<Int32>.stride
        while offset < Int(bufferSize) && buffer[offset] == 0 {
            offset += 1
        }
        if offset < Int(bufferSize) {
            let processName = String(cString: buffer + offset, encoding: .utf8)
            print("PID: \(pid), 进程名: \(processName ?? "未知")")
        }
    }
}

内容的提问来源于stack exchange,提问作者Thunder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 13:15:29