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返回的缓冲区并非直接以进程名称开头,其格式为:
- 首段是
int类型的参数个数(argc) - 后续才是以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
相关产品推荐
相关产品推荐

