Qt 獲取 CPU 使用率及內存占用大小
文章目錄
- Qt 獲取 CPU 使用率及內存占用大小
- 一、簡介
- 二、關鍵函數
- 2.1 獲取當前運行程序pid
- 2.2 通過pid獲取運行時間
- 2.3 通過pid獲取內存大小
- 三、具體實現
- 五、寫在最后
?
一、簡介
近期在使用軟件的過程中發現一個有意思的東西。如下所示:
該軟件可以顯示 CPU
使用率及內存大小和內存使用率。感覺比較有意思,于是就想著能不能通過 Qt
自己實現一套這樣的東西,這也是本文的由來。
那么,言歸正傳,本文將介紹 如何使用 Qt
獲取當前軟件的 CPU
使用率及內存大小。本文適合對 Qt
有一些基礎的朋友,對于一些簡單的地方我不會過多贅述,望諒解!!!
另外,本文闡述方法不適用于 Linux
,需要注意!!!
首先,我使用的環境如下所示:
- Windows 10 x64
- Qt 5.12.3
?
二、關鍵函數
本文專注于解決獲取 Qt
當前運行程序的 CPU
使用率及內存大小,因此本文通過獲取當前運行程序 pid
的形式獲取運行時間,通過運行時間計算得到 CPU
使用率。
2.1 獲取當前運行程序pid
在 Qt
中,可以通過如下所示的語句獲取當前程序 PID
:
QApplication::applicationPid();
?
2.2 通過pid獲取運行時間
首先,需要打開進程句柄,需要使用到如下所示的函數:
HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId
);
其中三個參數意義如下所示:
dwDesiredAccess
: 進程訪問權限bInheritHandle
: 是否允許子進程繼承此句柄,通常設為FALSE
dwProcessId
: 目標進程的PID
(進程標識符)
返回值意義如下所示:
- 成功:返回進程句柄(
HANDLE
) - 失敗:返回
NULL
,需調用GetLastError()
獲取錯誤碼
更詳細的解釋在官方網站:OpenProcess 函數 (processthreadsapi.h) - Win32 apps | Microsoft Learn
如若鏈接點擊無法跳轉,可自行復制打開:
- https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
其次,我們需要通過 PID
獲取運行時間信息,需要使用到如下所示的函數:
BOOL GetProcessTimes(HANDLE hProcess,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime
);
其參數意義如下所示:
hProcess
: 進程句柄lpCreationTime
: 進程的創建時間lpExitTime
: 進程的退出時間lpKernelTime
: 內核模式(如系統調用)下消耗的CPP
時間lpUserTime
: 用戶模式(應用程序代碼)下消耗的CPU
時間
返回參數意義如下所示:
- 成功:返回
TRUE
(非零值) - 失敗:返回
FALSE
(零值),需調用GetLastError()
獲取錯誤碼
更詳細的解釋在官方網站:getProcessTimes 函數 (processthreadsapi.h) - Win32 apps | Microsoft Learn
如若鏈接點擊無法跳轉,可自行復制打開:
- https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes
?
2.3 通過pid獲取內存大小
獲取進程使用內存大小,需要使用如下所示函數:
BOOL GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb
);
其參數意義如下所示:
Process
: 進程句柄ppsmemCounters
: 指向PROCESS_MEMORY_COUNTERS
結構的指針,用于接收內存統計信息cb
: 結構體大小,通常設為sizeof(PROCESS_MEMORY_COUNTERS)
返回參數意義如下所示:
- 成功:返回
TRUE
(非零值) - 失敗:返回
FALSE
(零值),需調用GetLastError()
獲取錯誤碼
其中需要注意的是 PROCESS_MEMORY_COUNTERS
結構體,其包含如下所示的成員參數:
typedef struct _PROCESS_MEMORY_COUNTERS {DWORD cb; // 結構體大小DWORD PageFaultCount; // 頁面錯誤次數SIZE_T PeakWorkingSetSize; // 工作集峰值(物理內存)SIZE_T WorkingSetSize; // 當前工作集大小SIZE_T QuotaPeakPagedPoolUsage; // 分頁池配額峰值SIZE_T QuotaPagedPoolUsage; // 當前分頁池配額SIZE_T QuotaPeakNonPagedPoolUsage; // 非分頁池配額峰值SIZE_T QuotaNonPagedPoolUsage; // 當前非分頁池配額SIZE_T PagefileUsage; // 頁面文件使用量SIZE_T PeakPagefileUsage; // 頁面文件使用峰值
} PROCESS_MEMORY_COUNTERS;
更詳細的解釋在官方網站:getProcessMemoryInfo 函數 (psapi.h) - Win32 apps | Microsoft Learn
如若鏈接點擊無法跳轉,可自行復制打開:
- https://learn.microsoft.com/zh-cn/windows/win32/api/psapi/nf-psapi-getprocessmemoryinfo
通過上述三個步驟即可輕松獲取當前運行程序的 CPU
使用率及內存大小。
?
三、具體實現
在 Qt
中推薦在線程中計算獲取這些信息。因為我們計算方法每 1s 獲取一次時間,計算與前 1s 時間的差值得到 CPU
占用率。如果不適用線程,將會阻塞主線程的執行。
這里我給出示例:
-
cpumontior.h
#ifndef CPUMONTIOR_H #define CPUMONTIOR_H#include "windows.h" #include <QObject> #include <QThread> #include "psapi.h" #include <QtMath>class CpuMontior : public QThread {Q_OBJECT public:explicit CpuMontior(DWORD pid, QObject *parent = nullptr);void setDec(int dec) {this->dec = dec;}protected:void run() override;private:DWORD pid;int dec;// 封裝轉換函數static ULONGLONG filetimeToULONGLONG(const FILETIME *ft) {ULARGE_INTEGER uli;uli.LowPart = ft->dwLowDateTime;uli.HighPart = ft->dwHighDateTime;return uli.QuadPart;}// bytes 單位轉換QString changeFileSize(qint64 fileSize){QStringList units;units << "B" << "KB" << "MB" << "GB" << "TB" << "PB";double mod = 1024.0;double size = fileSize;//qDebug() << size;int i = 0;long rest = 0;while (size >= mod && i < units.count()-1 ){rest= static_cast<long>(size) % static_cast<long>(mod);size /= mod;i++;}QString szResult = QString::number(qFloor(size));if( rest > 0){szResult += QString(".") + QString::number(rest).left(this->dec);}szResult += units[i];return szResult;}signals:/* 使用率信息 */void usageInfoSignal(QString cpuUsage, QString memUsage);public slots: };#endif // CPUMONTIOR_H
-
cpumontior.cpp
#include "cpumontior.h" #ifdef QT_DEBUG #include <QDebug> #endif/*!* @File : cpumontior.cpp* @Brief : 構造函數* @Details : None* @Param : void* @Return : void* @Author : Liu Jiahao* @Date : 2025-03-28 14:18:10* @Version : v1.1* @Copyright : Copyright By Liu Jiahao, All Rights Reserved**/ CpuMontior::CpuMontior(DWORD pid, QObject *parent) :QThread(parent), pid(pid), dec(2) {}/*!* @File : cpumontior.cpp* @Brief : 工作函數* @Details : None* @Param : void* @Return : void* @Author : Liu Jiahao* @Date : 2025-03-28 14:19:12* @Version : v1.1* @Copyright : Copyright By Liu Jiahao, All Rights Reserved**/ void CpuMontior::run() {// 獲取系統資源信息HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);if (!hProcess) return;FILETIME creationTime, exitTime, kernelTime, userTime;while (!isInterruptionRequested()) {// 第一次采樣if (!GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime, &userTime)) {break;}ULONGLONG kernel1 = filetimeToULONGLONG(&kernelTime);ULONGLONG user1 = filetimeToULONGLONG(&userTime);msleep(1000); // 每秒更新一次// 第二次采樣if (!GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime, &userTime)) {break;}ULONGLONG kernel2 = filetimeToULONGLONG(&kernelTime);ULONGLONG user2 = filetimeToULONGLONG(&userTime);// 計算差值ULONGLONG totalTime = (kernel2 - kernel1) + (user2 - user1);double cpuUsage = (totalTime / 10000.0) / 100.0; // 轉換為百分比// 內存使用率PROCESS_MEMORY_COUNTERS pmc;qint64 memoryUsage = 0;if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {memoryUsage = static_cast<qint64>(pmc.WorkingSetSize); // 單位:字節}// 通過信號發送emit usageInfoSignal(QString::number(cpuUsage, 'f', this->dec) + "%", changeFileSize(memoryUsage));} #ifdef QT_DEBUGqDebug() << "quit thread"; #endifCloseHandle(hProcess); }
增加 UI
進行顯示后,效果如下所示:
可以說,跟我開頭放的那個圖區別不大。具體的 UI
設計這里不進行贅述,大家可以自行構建。我在函數中使用了 emit usageInfoSignal(QString::number(cpuUsage, 'f', this->dec) + "%", changeFileSize(memoryUsage));
發送信號,大家可以根據這個信號 connect
槽函數進行實現。
?
五、寫在最后
本文介紹了 如何使用 Qt
獲取當前軟件的 CPU
使用率及內存大小。
題外話,現在覺得
AI
已經可以解決大部分遇到的問題,本文代碼部分也借助了AI
幫助,所有功能并非我原創。其實我也很惋惜,大家可以自行通過AI
解決這些問題,就不需要在網上到處搜索,那我寫博文似乎也失去了意義… 人工智能的發展不是壞事,只是改變了一些我們思考問題、解決問題的習慣。同時我也并不覺得 csdn 這個平臺有多好,也未經過我同意擅自將我的文章設置為僅VIP可見,這與我初心相悖。隨著工作繁忙,也很少有時間繼續寫下去…漸漸地也沒有了動力。下次更新不知道是什么時候,希望讀者海涵!
歡迎廣大讀者提出問題以及修改意見,本人看到后會給予回應,歡迎留言,后續會逐步進行開源!!!
另外,由于文章是作者手打的文字,有些地方可能文字會出錯,望諒解,也可私信聯系我,我對其進行更改。
-
個人CSDN賬號:劉梓謙_-CSDN博客
-
Gitee:劉佳豪 (liu-jiahaohappy) - Gitee.com
-
GitHub:Jiahao-Liu29 (github.com)