Linux

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > Linux > Linux查询当前进程或线程的资源使用

Linux如何查询当前进程或线程的资源使用情况

作者:小嵌同学

文章介绍如何通过Linux的/proc文件系统和API(如getrusage、sysinfo、times)获取App资源使用情况,用于性能分析和调试,涵盖进程状态、内存、CPU、网络等信息,同时说明了相关文件和系统的使用方法及注意事项

在工作中,我们排除app出现的一些性能/资源问题时,通常要先知道当前app的资源使用情况,方能进一步思考改进措施。

获取这些信息的途径有很多,我这里简单分享下两种:

1)从proc文件系统;

2)通过Linux 的API函数。

一、/proc/[PID]/下的各个文件

1、proc简介

/proc 目录是一个特殊的虚拟文件系统,它提供了对内核运行时信息的访问,包括进程、设备、网络、文件系统等各个方面的信息。

它不是一个真正的文件系统,而是基于内核数据结构的一个接口,通过这个接口可以获取系统的运行时状态。

下面是 /proc 目录的一些重要子目录和关键内容的说明:

除了上述目录和文件,/proc 目录下还有很多其他文件和目录,涵盖了系统和进程的各个方面的信息。

需要注意的是,/proc 目录下的文件是动态生成的,信息在进程运行时改变。读取这些文件时,请确保有足够的权限,并理解每个文件的含义和用途。此外,不要轻易对 /proc 目录下的文件进行修改,因为这可能会导致系统不稳定或损坏。

2、/proc/[PID]/详解

这些文件和目录提供了关于特定进程的多种信息,如进程状态、资源使用情况、环境变量等,通常被用于性能调优、调试以及资源管理方面,对于普通用户来说可能并不经常需要直接操作这些文件。通过读取这些文件,可以了解并监视系统中各个进程的情况。请注意,有些文件是符号链接,需要使用readlinkls -l等命令来获取其指向的真实路径。

知识补充:

命名空间(Namespace)在Linux系统中是一种用于隔离系统资源的机制。它允许在同一台物理机上创建多个隔离的环境,每个环境可以拥有自己独立的资源实例,例如进程ID、挂载点、网络、用户等。这种隔离使得不同的进程能够在同一系统上运行,而彼此之间互不干扰。

在Linux中,有多种类型的命名空间,包括但不限于以下几种:

通过使用命名空间,容器技术得以实现,并且不同的容器可以在相互隔离的环境中运行,从而实现更高效的资源利用和更好的安全性。

二、通过Linux API获取当前进程或线程的资源使用情况

要获取当前进程或线程的资源使用情况,可以使用Linux提供的一些系统调用或API。

以下是一些常用的方法:

1、getrusage

getrusage 是一个用于获取进程或线程的资源使用情况的系统调用函数,在 Linux 系统中的头文件 <sys/resource.h> 中定义。

#include <sys/time.h>
#include <sys/resource.h>

int getrusage(int who, struct rusage *usage);

参数who用于指定获取资源使用情况的对象,包括以下两个选项:

参数 usage 是一个指向 struct rusage 结构体的指针,用于存储获取到的资源使用情况信息。

//struct rusage 结构体包含了一系列字段,用于表示不同类型的资源使用情况
struct rusage {
    struct timeval ru_utime; /* user CPU time used */
    struct timeval ru_stime; /* system CPU time used */
    long   ru_maxrss;        /* maximum resident set size */
    long   ru_ixrss;         /* integral shared memory size */
    long   ru_idrss;         /* integral unshared data size */
    long   ru_isrss;         /* integral unshared stack size */
    long   ru_minflt;        /* page reclaims (soft page faults) */
    long   ru_majflt;        /* page faults (hard page faults) */
    long   ru_nswap;         /* swaps */
    long   ru_inblock;       /* block input operations */
    long   ru_oublock;       /* block output operations */
    long   ru_msgsnd;        /* IPC messages sent */
    long   ru_msgrcv;        /* IPC messages received */
    long   ru_nsignals;      /* signals received */
    long   ru_nvcsw;         /* voluntary context switches */
    long   ru_nivcsw;        /* involuntary context switches */
};

这些资源使用情况信息对于进程性能分析和系统监控非常有用。getrusage 函数返回的资源使用情况是关于当前进程或线程的信息。要获取其他进程的资源使用情况,需要使用相应的进程相关的系统调用(如 wait4),并将返回的 rusage 结构体作为参数传递给 wait4

wait4 是一个用于等待子进程结束并获取其状态信息的系统调用函数。在 Linux 系统中的头文件 <sys/wait.h> 中定义。wait4 函数的原型为:

pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);

其中参数含义如下:

wait4 函数会阻塞父进程,直到指定的子进程结束。当子进程结束后,父进程将获得子进程的退出状态信息存储在 status 中,并且如果传入了 rusage 参数,则会获取子进程的资源使用情况信息。

通常情况下,wait4 函数与 fork 函数结合使用,父进程通过 fork 创建子进程,然后通过 wait4 等待子进程结束,并获取其状态信息。这样可以实现父子进程之间的同步和协作。

#include <sys/resource.h>

int main() {
    struct rusage usage;

    getrusage(RUSAGE_SELF, &usage);

    // 打印CPU时间
    printf("CPU时间: %ld.%06ld 秒\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec);

    // 打印最大使用的内存
    printf("最大内存使用量: %ld 字节\n", usage.ru_maxrss);

    // 其他资源使用情况,可以在usage结构体中查看
    // ...

    return 0;
}

2、sysinfo

sysinfo 是一个用于获取系统信息的系统调用函数,在 Linux 系统中的头文件 <sys/sysinfo.h> 中定义。

函数原型如下:

int sysinfo(struct sysinfo *info);

参数 info 是一个指向 struct sysinfo 结构体的指针,用于存储获取到的系统信息。

//Since Linux 2.3.23 (i386) and Linux 2.3.48 (all architectures) the structure is:
struct sysinfo {
    long uptime;             /* Seconds since boot */
    unsigned long loads[3];  /* 1, 5, and 15 minute load averages */
    unsigned long totalram;  /* Total usable main memory size */
    unsigned long freeram;   /* Available memory size */
    unsigned long sharedram; /* Amount of shared memory */
    unsigned long bufferram; /* Memory used by buffers */
    unsigned long totalswap; /* Total swap space size */
    unsigned long freeswap;  /* Swap space still available */
    unsigned short procs;    /* Number of current processes */
    unsigned long totalhigh; /* Total high memory size */
    unsigned long freehigh;  /* Available high memory size */
    unsigned int mem_unit;   /* Memory unit size in bytes */
    char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding to 64 bytes */
};

sysinfo 函数的返回值为 0 表示成功,-1 表示失败,并且可以通过 errno 来获取具体错误信息。

#include <sys/sysinfo.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    struct sysinfo info;

    sysinfo(&info);

    // 打印总内存大小
    printf("总内存大小: %ld 字节\n", info.totalram * info.mem_unit);

    // 打印已使用内存大小
    printf("已使用内存大小: %ld 字节\n", (info.totalram - info.freeram) * info.mem_unit);

    // 其他资源使用情况,可以在info结构体中查看
    // ...

    return 0;
}

struct sysinfo 结构体中,loads 数组中的数值表示了负载值乘以 2^16 的结果,这是因为 sysinfo 结构体中的 loads 数组使用了 unsigned long 类型。

在 Linux 内核中,负载值是以固定点数的格式表示的,使用了定点数表示方式来保留小数部分。在这里,每个负载值都被乘以了 2^16(65536),以便将小数部分转换为整数。

这种表示方式的好处在于,它可以比较精确地表示系统的负载情况,同时又不需要使用浮点数来表示,因为浮点数的运算会耗费相对更多的 CPU 时间。通过将负载值乘以一个固定的倍数(2^16),可以在不牺牲太多精度的情况下,使用整数进行表示和计算,这样会更高效。

当我们从 struct sysinfo 结构体中获取负载值时,需要将其除以 2^16 来得到真实的负载值。例如,在上面的示例代码中,打印负载值时并没有除以 2^16,因此实际的负载值应当是 info.loads[x] / 65536 才能得到系统的实际负载情况。

总之,通过将负载值乘以 2^16 来表示,Linux 内核可以在保持较高精度的同时,使用更高效的整数表示方式,用于存储和计算系统的负载情况。

3、times

times 函数是一个用于获取进程和子进程的系统和用户 CPU 时间的系统调用,其原型如下:

#include <sys/times.h>

clock_t times(struct tms *buf);

struct tms 结构包含了进程和子进程的 CPU 时间信息,其定义如下:

struct tms {
    clock_t tms_utime;  // 进程在用户态花费的时间
    clock_t tms_stime;  // 进程在内核态花费的时间
    clock_t tms_cutime; // 所有已终止子进程在用户态花费的时间
    clock_t tms_cstime; // 所有已终止子进程在内核态花费的时间
};

示例代码如下所示,演示了如何使用 times 函数来获取进程的 CPU 时间信息:

#include <stdio.h>
#include <sys/times.h>
#include <time.h>
#include <unistd.h>

int main() {
    struct tms tms_buf;
    clock_t start, end;

    // 获取起始时间
    start = times(&tms_buf);
    printf("Starting time: %ld\n", start);

    // 模拟一些工作
    for (int i = 0; i < 100000000; ++i) {
        // do something
    }

    // 获取结束时间
    end = times(&tms_buf);
    printf("Ending time: %ld\n", end);

    // 计算 CPU 时间消耗
    clock_t user_time = tms_buf.tms_utime;
    clock_t sys_time = tms_buf.tms_stime;
    printf("User CPU time: %ld\n", user_time);
    printf("System CPU time: %ld\n", sys_time);

    return 0;
}

这个示例代码中,我们首先调用 times 函数获取了进程的 CPU 时间信息,并输出了起始时间。然后进行了一些模拟工作,之后再次调用 times 函数获取了结束时间,最后计算了用户态和内核态的 CPU 时间消耗。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文