C++获取程序内存占用

2 篇文章 0 订阅
2 篇文章 0 订阅

C++获取程序内存占用

windows中获取内存占用

#include <windows.h>
#include <psapi.h>
#pragma comment(lib,"psapi.lib")
#include <vector>
#include <iostream>
using namespace std;


int main() {

	vector<int> v;

	for (int i = 0; i < 10000000; i++) {
		v.push_back(i);
	}

	HANDLE handle = GetCurrentProcess();
	PROCESS_MEMORY_COUNTERS pmc;//以字节为单位
	GetProcessMemoryInfo(handle, &pmc, sizeof(pmc));
	std::cout << pmc.WorkingSetSize << endl;


	return 0;
}

当循环中i=1000000,输出为
在这里插入图片描述
当循环中i=1000,输出为
在这里插入图片描述

细节

如何实现的?
利用了两个包:windows.h和psapi.h
HANDLE是windows.h中的,用于获取当前进程。
PROCESS_MEMORY_COUNTERS是psapi.h中的,用于存储所占内存大小。
GetProcessMemoryInfo(HANDLE,&PROCESS_MERORY_COUNTERS,sizeof(PROCESS_MEMORY_COUNTERS))也是psapi.h中的,用于获取进程占用内存大小,并存储在PROCESS_MEMORY_COUNTERS类型的变量中,单位是字节。

#pragma comment(lib,“psapi.lib”) 是什么?
这是vscode引入库的操作,人为的告诉连接器,需要静态链接某个库。显然,因为是静态链接,故而只影响编译时。优点是不用再去配置多个属性表。
但是gcc不支持这个命令,所以DevC++, VSC, Codeblocks啥的都不能用

C++中获取内存占用

#include <iostream>
#include <thread>
#include <chrono>
#include <string.h>

#ifdef WIN32
#include <windows.h>  
#include <psapi.h>  
//#include <tlhelp32.h>
#include <direct.h>
#include <process.h>
#else
#include <sys/stat.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <unistd.h>
#endif

// get current process pid
inline int GetCurrentPid()
{
    return getpid();
}

// get specific process cpu occupation ratio by pid
#ifdef WIN32
// 
static uint64_t convert_time_format(const FILETIME* ftime)
{
    LARGE_INTEGER li;

    li.LowPart = ftime->dwLowDateTime;
    li.HighPart = ftime->dwHighDateTime;
    return li.QuadPart;
}
#else
// FIXME: can also get cpu and mem status from popen cmd
// the info line num in /proc/{pid}/status file
#define VMRSS_LINE 22
#define PROCESS_ITEM 14

static const char* get_items(const char* buffer, unsigned int item)
{
    // read from buffer by offset
    const char* p = buffer;

    int len = strlen(buffer);
    int count = 0;

    for (int i = 0; i < len; i++)
    {
        if (' ' == *p)
        {
            count++;
            if (count == item - 1)
            {
                p++;
                break;
            }
        }
        p++;
    }

    return p;
}

static inline unsigned long get_cpu_total_occupy()
{
    // get total cpu use time

    // different mode cpu occupy time
    unsigned long user_time;
    unsigned long nice_time;
    unsigned long system_time;
    unsigned long idle_time;

    FILE* fd;
    char buff[1024] = { 0 };

    fd = fopen("/proc/stat", "r");
    if (nullptr == fd)
        return 0;

    fgets(buff, sizeof(buff), fd);
    char name[64] = { 0 };
    sscanf(buff, "%s %ld %ld %ld %ld", name, &user_time, &nice_time, &system_time, &idle_time);
    fclose(fd);

    return (user_time + nice_time + system_time + idle_time);
}

static inline unsigned long get_cpu_proc_occupy(int pid)
{
    // get specific pid cpu use time
    unsigned int tmp_pid;
    unsigned long utime;  // user time
    unsigned long stime;  // kernel time
    unsigned long cutime; // all user time
    unsigned long cstime; // all dead time

    char file_name[64] = { 0 };
    FILE* fd;
    char line_buff[1024] = { 0 };
    sprintf(file_name, "/proc/%d/stat", pid);

    fd = fopen(file_name, "r");
    if (nullptr == fd)
        return 0;

    fgets(line_buff, sizeof(line_buff), fd);

    sscanf(line_buff, "%u", &tmp_pid);
    const char* q = get_items(line_buff, PROCESS_ITEM);
    sscanf(q, "%ld %ld %ld %ld", &utime, &stime, &cutime, &cstime);
    fclose(fd);

    return (utime + stime + cutime + cstime);
}
#endif

inline float GetCpuUsageRatio(int pid)
{
#ifdef WIN32
    static int64_t last_time = 0;
    static int64_t last_system_time = 0;

    FILETIME now;
    FILETIME creation_time;
    FILETIME exit_time;
    FILETIME kernel_time;
    FILETIME user_time;
    int64_t system_time;
    int64_t time;
    int64_t system_time_delta;
    int64_t time_delta;

    // get cpu num
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    int cpu_num = info.dwNumberOfProcessors;

    float cpu_ratio = 0.0;

    // get process hanlde by pid
    HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    // use GetCurrentProcess() can get current process and no need to close handle

    // get now time
    GetSystemTimeAsFileTime(&now);

    if (!GetProcessTimes(process, &creation_time, &exit_time, &kernel_time, &user_time))
    {
        // We don't assert here because in some cases (such as in the Task Manager)  
        // we may call this function on a process that has just exited but we have  
        // not yet received the notification.  
        printf("GetCpuUsageRatio GetProcessTimes failed\n");
        return 0.0;
    }

    // should handle the multiple cpu num
    system_time = (convert_time_format(&kernel_time) + convert_time_format(&user_time)) / cpu_num;
    time = convert_time_format(&now);

    if ((last_system_time == 0) || (last_time == 0))
    {
        // First call, just set the last values.  
        last_system_time = system_time;
        last_time = time;
        return 0.0;
    }

    system_time_delta = system_time - last_system_time;
    time_delta = time - last_time;

    CloseHandle(process);

    if (time_delta == 0)
    {
        printf("GetCpuUsageRatio time_delta is 0, error\n");
        return 0.0;
    }

    // We add time_delta / 2 so the result is rounded.  
    cpu_ratio = (int)((system_time_delta * 100 + time_delta / 2) / time_delta); // the % unit
    last_system_time = system_time;
    last_time = time;

    cpu_ratio /= 100.0; // convert to float number

    return cpu_ratio;
#else
    unsigned long totalcputime1, totalcputime2;
    unsigned long procputime1, procputime2;

    totalcputime1 = get_cpu_total_occupy();
    procputime1 = get_cpu_proc_occupy(pid);

    // FIXME: the 200ms is a magic number, works well
    usleep(200000); // sleep 200ms to fetch two time point cpu usage snapshots sample for later calculation

    totalcputime2 = get_cpu_total_occupy();
    procputime2 = get_cpu_proc_occupy(pid);

    float pcpu = 0.0;
    if (0 != totalcputime2 - totalcputime1)
        pcpu = (procputime2 - procputime1) / float(totalcputime2 - totalcputime1); // float number

    int cpu_num = get_nprocs();
    pcpu *= cpu_num; // should multiply cpu num in multiple cpu machine

    return pcpu;
#endif
}

// get specific process physical memeory occupation size by pid (MB)
inline float GetMemoryUsage(int pid)
{
#ifdef WIN32
    uint64_t mem = 0, vmem = 0;
    PROCESS_MEMORY_COUNTERS pmc;

    // get process hanlde by pid
    HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc)))
    {
        mem = pmc.WorkingSetSize;
        vmem = pmc.PagefileUsage;
    }
    CloseHandle(process);

    // use GetCurrentProcess() can get current process and no need to close handle

    // convert mem from B to MB
    return mem / 1024.0 / 1024.0;

#else
    char file_name[64] = { 0 };
    FILE* fd;
    char line_buff[512] = { 0 };
    sprintf(file_name, "/proc/%d/status", pid);

    fd = fopen(file_name, "r");
    if (nullptr == fd)
        return 0;

    char name[64];
    int vmrss = 0;
    for (int i = 0; i < VMRSS_LINE - 1; i++)
        fgets(line_buff, sizeof(line_buff), fd);

    fgets(line_buff, sizeof(line_buff), fd);
    sscanf(line_buff, "%s %d", name, &vmrss);
    fclose(fd);

    // cnvert VmRSS from KB to MB
    return vmrss / 1024.0;
#endif
}

int main()
{
    // launch some task to occupy cpu and memory
    for (int i = 0; i < 5; i++)
        std::thread([]
            {
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
            }).detach();

    int current_pid = GetCurrentPid(); // or you can set a outside program pid
    float cpu_usage_ratio = GetCpuUsageRatio(current_pid);
    float memory_usage = GetMemoryUsage(current_pid);

    while (true)
    {
        std::cout << "current pid: " << current_pid << std::endl;
        std::cout << "cpu usage ratio: " << cpu_usage_ratio * 100 << "%" << std::endl;
        std::cout << "memory usage: " << memory_usage << "MB" << std::endl;

        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

    return 0;
}

编译指令: g++ -o temp.exe temp.cpp -lpthread
编译时需加上-lpthread,因为pthread不是Linux下的默认的库,也就是在链接的时候,无法找到phread库中哥函数的入口地址,于是链接会失败

Question

1.inline关键字是什么作用?

inline关键字用在函数体前面,用于将函数设置为内联函数,可以减少频繁调用同一函数时所造成的资源消耗(如访问栈空间、保存现场等的开销)。为什么可以实现这样的效果呢?这就要说到什么是内联函数,其实现原理是啥。

所谓内联函数,就是在编译阶段时,将函数嵌入到每一个调用该函数的地方,使其在运行时不需要去访问栈空间来找到函数位置从而造成一系列资源的开销。

inline需要写在函数实现的前面,而不能是函数声明的前面。也就是所谓的“用于实现的关键字”,而非“用于声明的关键字”。

2.std::chrono是啥?

std::chrono是c++标准库提供的一个时间处理库,提供一系列关于时间的工具。

3.std::thread()用法,std::thread([]{}).detach()怎么理解 ?

detach和join。detach()后主线程和子线程分离,主线程不用等待子线程。join()后,主线程需要等待子线程执行结束。

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值