Linux C 获取进程的 CPU 和内存数据

Linux 中的 CPU 和内存数据

有时候,在程序运行过程中需要考虑到 CPU 和内存的占用情况,也需要观察系统 CPU 和内存的使用情况,虽然 Linux 上有对应的指令可以很方便的获取这些数据,但这些指令毕竟不是接口,不能直接当 API 调用。本章通过 Linux C 语言实现获取进程 CPU 和内存占用的接口。

在 Linux 中,所有即时数据(如 CPU 和内存数据)都位于 /proc/ 目录中,进程的即时数据位于 /proc/{pid}/ 目录中。说白了,要获取 CPU 和内存的利用率,就是要去解析这些文件。

但 CPU 数据有所不同,/proc/ 中保存的 CPU 数据都是自系统开机以来的时钟数 ,要得到 CPU 的利用率就需要做统计运算,计算公式如下
平均 C P U 利用率 = C P U 工作时间 2 − C P U 工作时间 1 C P U 总时间 2 − C P U 总时间 1 平均CPU利用率 = \frac{CPU工作时间2-CPU工作时间1}{CPU总时间2-CPU总时间1} 平均CPU利用率=CPU总时间2CPU总时间1CPU工作时间2CPU工作时间1
注意: C P U 工作时间 = C P U 总时间 − C P U 空闲时间 CPU工作时间=CPU总时间-CPU空闲时间 CPU工作时间=CPU总时间CPU空闲时间 。因为这里计算的是一个统计值,需要一段时间间隔,一般设置在 0~1s 之间,所以该过程会阻塞一段时间。当然,也可以使用一个单独线程去计算,将结果放入一个全局变量中。


C 语言获取 CPU 和内存数据

介绍完 CPU 利用率的原理,就可以直接使用 C 语言获取这些数据了。若是还有不明白的地方也不要紧,代码中有详细的注释。代码分两部分:接口声明和接口实现,只依赖系统头文件,可在项目中直接使用。

接口声明代码:

// CPU利用率,包含系统CPU和本进程CPU的利用率
struct CpuUsed {
    unsigned long sys_used;
    unsigned long proc_used;
};

// 获取CPU利用率,如CPU利用率为60%,则返回60。
// 系统CPU数据位于文件/proc/stat中,进程CPU数据位于/proc/{pid}/stat中,
// 文件中只有自系统启动以来的CPU时钟数,利用率需要手动进行统计和计算,
// 默认统计时间间隔为500ms(一般设置在0~1s之间),所以该函数会阻塞ms的时间。
CpuUsed GetCpuUsed(int ms = 500); 

// 获取系统已使用的内存,单位MB。total为输出参数,表示总内存
// 系统内存数据位于文件/proc/meminfo中
int GetSystemMemUsed(int &total);

// 获取本进程已使用的内存,单位MB。若不足1MB,返回1
// 进程内存数据位于文件/proc/{pid}/statm中
int GetProcessMemUsed(void);

接口实现代码:

#include <unistd.h>         // for getpid and usleep
#include <sys/sysinfo.h>    // for get_nprocs

// cpu信息的结构体,读文件/proc/stat
// see: https://man7.org/linux/man-pages/man5/proc.5.html
struct CpuStat {
    char name[8];               // 设备名,一般值为pu
    unsigned long user;         // 用户态的CPU时间(单位:0.01s)
    unsigned long nice;         // nice值为负的进程所占用的CPU时间(单位:0.01s)
    unsigned long system;       // 处于核心态的运行时间(单位:0.01s)
    unsigned long idle;         // 除IO等待时间意外其他等待时间(单位:0.01s)
};

// 内存信息的结构体,读文件/proc/meminfo
struct MemInfo {
    unsigned long total;        // MemTotal 总内存
    unsigned long free;         // MemFree  空闲内存
    unsigned long avaliable;    // MemAvailable 可用内存,约等于 MemFree + Buffer + Catch
};

// 解析/proc/stat文件,获取CPU信息
static void GetSystemCpuStat(CpuStat *s) {
    memset(s, 0, sizeof(CpuStat));

    char buf[256];
    FILE *fd = fopen("/proc/stat", "r");
    assert(fd != nullptr);
    fgets(buf, sizeof(buf), fd);
    sscanf(buf, "%s  %lu %lu %lu %lu", s->name, &s->user, &s->nice, &s->system, &s->idle);
    fclose(fd);
    // fprintf(stdout, "%s: %lu %lu %lu %lu\n", s->name, s->user, s->nice, s->system, s->idle);
}

// 向后偏移14项,正好是utime
#define PROCESS_ITEM 14

// 获取/proc/{pid}/stat中CPU的使用信息,主要是
// (14) utime  %lu
// (15) stime  %lu
// (16) cutime  %ld
// (17) cstime  %ld
static unsigned long GetProcessCpuTime(int pid) {
    // 计算当前进程对应的文件名
    char filename[64];
    snprintf(filename, sizeof(filename) - 1, "/proc/%d/stat", pid);

    char buf[1024];
    FILE *fd = fopen(filename, "r");
    assert(fd != nullptr);
    fgets(buf, sizeof(buf), fd);
    // fprintf(stdout, "%s: %s", filename, buf);
    fclose(fd);

    // 向后偏移,直至utime项
    int count = 1;
    const char *p = buf;
    while (*p != '\0') {
        if (*p++ == ' ') {
            count++;
            if (count == PROCESS_ITEM) break;
        }
    }
    if (*p == '\0') return 0;

    unsigned long utime = 0;    // user time
    unsigned long stime = 0;    // kernel time
    unsigned long cutime = 0;   // all user time
    unsigned long cstime = 0;   // all dead time
    sscanf(p, "%ld %ld %ld %ld", &utime, &stime, &cutime, &cstime);
    // fprintf(stdout, "proc[%d]: %lu %lu %lu %lu\n", pid, utime, stime, cutime, cstime);
    return (utime + stime + cutime + cstime);
}

// 获取CPU利用率,如CPU利用率为60%,则返回60
CpuUsed GetCpuUsed(int ms) {
    CpuUsed used;
    used.sys_used = used.proc_used = 0;

    int pid = getpid();
    CpuStat s1, s2;
    GetSystemCpuStat(&s1);
    unsigned long proc_time1 = GetProcessCpuTime(pid);

    usleep(ms * 1000);

    GetSystemCpuStat(&s2);
    unsigned long proc_time2 = GetProcessCpuTime(pid);

    // 计算CPU利用率:使用时间/总时间
    unsigned int sys_used1 = s1.user + s1.nice + s1.system; 
    unsigned int sys_used2 = s2.user + s2.nice + s2.system;
    unsigned int sys_total1 = sys_used1 + s1.idle; 
    unsigned int sys_total2 = sys_used2 + s2.idle;
    
    if (sys_total1 < sys_total2) {
        used.sys_used = 100 * (sys_used2 - sys_used1) / (sys_total2 - sys_total1);
        // 多线程,需要乘CPU core数量
        used.proc_used = get_nprocs() * 100 * (proc_time2 - proc_time1) / (sys_total2 - sys_total1);
    }
    
    return used;
}

// 解析/proc/meminfo文件,获取内存信息
// MemTotal %lu
// MemFree %lu
// MemAvailable %lu (since Linux 3.14)
static void GetSystemMeminfo(MemInfo *info) {
    memset(info, 0, sizeof(MemInfo));

    char buf[128];
    char name[64];
    char unit[64];
    FILE *fd = fopen("/proc/meminfo", "r");
    assert(fd != nullptr);
    fgets(buf, sizeof(buf), fd);
    sscanf(buf, "%s %u %s", name, &info->total, unit);
    fgets(buf, sizeof(buf), fd);
    sscanf(buf, "%s %u %s", name, &info->free, unit);
    fgets(buf, sizeof(buf), fd);
    sscanf(buf, "%s %u %s", name, &info->avaliable, unit);
    fclose(fd);
    // fprintf(stdout, "mem: %u %u %u\n", info->total, info->free, info->avaliable);
}

// 解析/proc/{pid}/statm文件,获取内存信息,前两项为
// size (pages) 任务虚拟地址空间的大小 VmSize/4,单位 KB
// resident(pages) 应用程序正在使用的物理内存的大小 VmRSS/4,单位 KB
static unsigned long GetProcessMeminfo(int pid) {
    // 计算当前进程对应的文件名
    char filename[64];
    snprintf(filename, sizeof(filename) - 1, "/proc/%d/statm", pid);

    char buf[256];
    FILE *fd = fopen(filename, "r");
    assert(fd != nullptr);
    fgets(buf, sizeof(buf), fd);
    fclose(fd);

    unsigned long size = 0;
    unsigned long resident = 0;
    sscanf(buf, "%lu %lu", &size, &resident);
    // fprintf(stdout, "proc mem: %u %u\n", size, resident);
    return resident * 4;
}

// 获取系统已使用的内存,单位MB。total为输出参数,表示总内存
int GetSystemMemUsed(int &total) {
    MemInfo info;
    GetSystemMeminfo(&info);
    total = info.total / 1024;
    return (total - info.avaliable / 1024);
}

// 获取本进程已使用的内存,单位MB
int GetProcessMemUsed(void) {
    unsigned long mem_used = GetProcessMeminfo(getpid());
    return ((mem_used < 1024) ? 1 : mem_used / 1024);
}

其中,在获取系统内存时,文件 /proc/stat/meminfo 中有如下三项:

  • MemTotal

    系统总内存数,可简单理解为系统的物理内存。

  • MemFree

    系统空闲内存数,即系统中尚未被使用的内存。

  • MemAvailable

    系统可用内存数,之所以有这个概念是因为 Linux 中有些内存虽已被使用,但仍可以回收,比如 Cache/Buffer、Slab 中都有一部分是能被回收的,所以 MemFree 不能代表全部可用的内存。可以简单的理解为:MemAvailable ≈ MemFree + Buffers + Cached,当然这是一个估值。

在网上看见过一个描述,个人感觉比较准确,在此分享一下:

MemAvailable 与 MemFree 的关键区别在于:MemAvailable 是应用程序层面的内存大小,而 MemFree 是系统层面的内存大小。


参考资料

  1. proc(5) — Linux manual page
  2. C++获取对应进程的cpu和内存使用情况(支持linux和windows)
  3. LINUX C语言 定时查看CPU,内存和磁盘利用率
  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Linux系统中,获取指定进程CPU占用率c可以使用top命令或ps命令。这两个命令都可以查看系统中运行进程信息,包括进程CPU占用率。 使用top命令获取指定进程CPU占用率可以通过以下步骤实现: 1. 打开终端,输入top命令。 2. 按下shift+p,然后输入要查看的进程号或名称,回车。 3. top命令将会显示该进程CPU占用率。 使用ps命令获取指定进程CPU占用率可以通过以下步骤实现: 1. 打开终端,输入ps命令,加上选项p和进程号或名称。 2. 在选项中加上-o选项,后面输入%cpu或%CPU。 3. 执行该命令,将会显示该进程CPU占用率。 以上两个命令都可以实现获取指定进程CPU占用率的功能,具体使用哪种方法取决于用户的需求。需要注意的是,这两个命令获取CPU占用率是该进程在系统整体CPU使用率中的占比,并不是该进程的实际CPU使用率。如果需要获取进程的实际CPU使用率,需要使用更为专业的工具或命令。 ### 回答2: 在Linux系统中,我们可以通过多种方式来获取指定进程CPU占用率。以下是几个常用的方法: 1. top命令 top命令是一个基于终端的系统监控工具,它能够显示系统中进程的实时信息,包括CPU占用率。要获取指定进程CPU占用率,可以按下“Shift + P”键,然后输入进程ID或进程名称即可。 2. ps命令 ps命令是另外一个常用的用于获取进程信息的命令。它可以显示所有进程的信息,也可以根据进程ID或进程名称来获取指定进程的信息。要获取指定进程CPU占用率,可以使用如下命令: ps -o pid,%cpu,comm -p 进程ID 其中,“%cpu”表示CPU占用率,它是ps命令的一个输出参数。 3. pidstat命令 pidstat是一个用于进程性能监测的工具,它可以显示每个进程CPU占用率、内存占用率等详细信息。要获取指定进程CPU占用率,可以使用如下命令: pidstat -p 进程ID 其中,“-p”参数表示指定要监测的进程ID。 4. top -n命令 top命令还可以使用“-n”参数来指定监测次数。这样,我们可以在一定时间内获取指定进程的平均CPU占用率。例如,要获取进程ID为123的进程在10秒内的平均CPU占用率,可以使用如下命令: top -b -n 10 -d 1 -p 123 |grep "123" 其中,“-b”表示以批处理模式运行top命令,“-n”表示监测次数,“-d”表示监测间隔,“-p”表示要监测的进程ID。最后使用grep命令来过滤输出信息,只保留目标进程的信息。 ### 回答3: 获取指定进程 CPU 占用率的方法,在 Linux 系统中有多种实现方式。本文将介绍两种常见的方法: 方法一:使用 top 命令 top 命令可以查看系统中所有进程CPU 占用情况,可以通过 top 命令获取指定进程CPU 占用率。具体方法如下: 1. 打开终端,输入 top 命令; 2. 按下“Shift + P”组合键,进入按 CPU 占用率排序模式; 3. 找到目标进程对应的 PID(进程 ID),使用“k”命令杀掉该进程并记录其 CPU 占用率,或记录当前 CPU 占用率。 方法二:使用 ps 命令和 awk 命令 ps 命令可以列出系统中所有进程的信息,awk 命令可以对列数据进行处理。使用这两个命令可以获取指定进程CPU 占用率。具体方法如下: 1. 打开终端,输入“ps aux | grep [进程名称]”命令,获取目标进程的 PID; 2. 输入“top -p [PID]”命令,实时监控目标进程CPU 占用率,并记录需要的信息; 3. 按下“Ctrl + C”组合键退出 top 命令。 需要注意的是,在使用这两种方法获取 CPU 占用率时,数据的精确性和稳定性都受到系统负载等因素的影响。为获得更准确的结果,可以多次测量、取平均值,或使用更具专业性的系统监控工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值