在Objective-C中获取类似top命令的系统进程信息,可以通过系统级API实现,以下为详细实现方案,适用于macOS开发(iOS因沙盒限制无法获取其他进程信息):
核心实现步骤
获取进程ID列表
- (NSArray *)getAllProcessIDs {
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
size_t length = 0;
// 获取数据长度
sysctl(mib, 4, NULL, &length, NULL, 0);
// 分配内存
struct kinfo_proc *processList = malloc(length);
sysctl(mib, 4, processList, &length, NULL, 0);
int processCount = (int)(length / sizeof(struct kinfo_proc));
NSMutableArray *pids = [NSMutableArray array];
for (int i = 0; i < processCount; i++) {
[pids addObject:@(processList[i].kp_proc.p_pid)];
}
free(processList);
return [pids copy];
}
获取单个进程详细信息
#import <libproc.h>
#import <mach/mach.h>
- (NSDictionary *)processInfoForPID:(pid_t)pid {
// 1. 获取进程名称
char name[256];
proc_name(pid, name, sizeof(name));
NSString *processName = [NSString stringWithUTF8String:name];
// 2. 获取CPU使用率(需两次采样计算)
static NSMutableDictionary *prevTimeDict;
if (!prevTimeDict) prevTimeDict = [NSMutableDictionary dictionary];
struct proc_taskinfo taskInfo;
proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &taskInfo, sizeof(taskInfo));
double cpuUsage = 0.0;
if (prevTimeDict[@(pid)]) {
uint64_t prevTime = [prevTimeDict[@(pid)] unsignedLongLongValue];
uint64_t timeDiff = taskInfo.pti_total_user + taskInfo.pti_total_system - prevTime;
cpuUsage = (timeDiff / 10000000.0); // 转换为百分比
}
prevTimeDict[@(pid)] = @(taskInfo.pti_total_user + taskInfo.pti_total_system);
// 3. 获取内存占用
struct proc_regioninfo regionInfo;
proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, ®ionInfo, sizeof(regionInfo));
unsigned long memoryUsage = regionInfo.pri_private_resident_size / 1024; // KB
return @{
@"pid": @(pid),
@"name": processName,
@"cpu": @(cpuUsage),
@"memory": @(memoryUsage)
};
}
整合所有进程数据
- (NSArray *)getTopProcesses {
NSArray *pids = [self getAllProcessIDs];
NSMutableArray *processes = [NSMutableArray array];
for (NSNumber *pidNum in pids) {
pid_t pid = [pidNum intValue];
NSDictionary *info = [self processInfoForPID:pid];
if (info) [processes addObject:info];
}
// 按CPU使用率排序
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"cpu" ascending:NO];
return [processes sortedArrayUsingDescriptors:@[sortDescriptor]];
}
关键说明
-
权限要求:
- 需要开启
com.apple.security.get-task-all权限(在Entitlements文件中) - macOS应用需签名并开启沙盒的
Allow Debugging权限
- 需要开启
-
性能优化:
- 避免频繁调用(建议采样间隔≥1秒)
- 使用缓存存储上次采样时间
- 过滤
pid=0的系统进程
-
iOS限制:
- iOS只能获取当前应用的信息
- 使用
NSProcessInfo获取当前进程数据:double cpu = [NSProcessInfo processInfo].processorLoad; long memory = [NSProcessInfo processInfo].physicalMemory / 1024;
输出示例
[
{"pid": 123, "name": "Xcode", "cpu": 45.2, "memory": 102400},
{"pid": 456, "name": "Safari", "cpu": 22.1, "memory": 87600},
...
]
替代方案(系统命令)
若无需实时控制,可直接调用top命令:
NSTask *task = [[NSTask alloc] init]; [task setLaunchPath:@"/usr/bin/top"]; [task setArguments:@[@"-l", @"1", @"-n", @"10"]]; // 采样1次,前10进程 NSPipe *pipe = [NSPipe pipe]; [task setStandardOutput:pipe]; [task launch]; NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile]; NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
注意事项
- 内存管理:使用
free()释放malloc分配的内存 - 错误处理:检查
sysctl/proc_pidinfo返回值 - 实时性:CPU使用率需两次采样计算差值
- 沙盒限制:完整功能需关闭App Sandbox
引用说明:本文实现基于Apple官方文档 proc_info(2) 及 sysctl(3) 系统调用。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/5061.html