Windows下限制进程的CPU和内存使用
缘起
有时候我们想要限制某个程序的CPU,使其最多占用20%的CPU;有时候我们想要限制程序的内存,使其最多占用2GB的内存。Linux下可以通过cgroup来实现,windows下怎么办呢……
这一点可以通过Windows API中的JobObject来实现~
官方文档:
Github上别人写好的工具(不过这是用C#写的):
简介
简单来说就是windows提供了一个叫做JobObject的东东,可以限制进程的CPU利用率、CPU核心、内存、网络带宽、管理员权限等等。功能还是很强大的……
使用流程如下:
- 通过
CreateJobObjectA
创建一个 JobObject - 创建一个job information的结构体,设置自己要控制的值。有很多不同的结构体声明,分别用来控制不同的属性……
- 通过
SetInformationJobObject
来将刚才创建的information设给JobObject - 通过
AssignProcessToJobObject
来将某个进程分配给Job Object,这样,这个进程就会受到Job Object的控制了
例程
这个是我随手糊的,反正跑起来就行了,所以代码写得比较烂,异常和错误也没处理,但反正效果是达到了…… 例子里只限制了CPU……(发现Github上有现成的程序之后就懒得去写内存限制了,反正就是用一个不同的information而已……)
注意限制子进程不需要管理员权限。如果要限制已经存在的进程,就需要用管理员权限运行。
- snippet.cpp
#include <windows.h> #include <stdexcept> #include <iostream> #include <string> using namespace std::string_literals; class Process { public: Process() = default; Process(const Process&) = delete; Process operator=(const Process&) = delete; virtual ~Process() {}; virtual HANDLE handle() const = 0; virtual void wait() const = 0; }; class AttachProcess : public Process { private: HANDLE h; public: explicit AttachProcess(DWORD pid) { h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (h == NULL) throw std::runtime_error("Failed to open process"); } ~AttachProcess() { CloseHandle(h); } HANDLE handle() const override { return h; } void wait() const override { WaitForSingleObject(h, INFINITE); } }; class ChildProcess : public Process { private: STARTUPINFOA si; PROCESS_INFORMATION pi; public: ChildProcess(const ChildProcess&) = delete; ChildProcess operator=(const ChildProcess&) = delete; explicit ChildProcess(LPCSTR applicationPath) { ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); if (!CreateProcessA(applicationPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { throw std::runtime_error("Failed to create child process!"); } } void start() { ResumeThread(pi.hThread); } void wait() const override { WaitForSingleObject(pi.hProcess, INFINITE); } HANDLE handle() const override { return pi.hProcess; } ~ChildProcess() { WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } }; class JobObjectInformation { public: JobObjectInformation() = default; JobObjectInformation(const JobObjectInformation&) = delete; JobObjectInformation operator=(const JobObjectInformation&) = delete; virtual JOBOBJECTINFOCLASS getClass() const = 0; virtual DWORD length() const = 0; virtual LPVOID informationPtr() const = 0; virtual ~JobObjectInformation() {}; }; class JobObject { public: JobObject(const JobObject&) = delete; JobObject operator=(const JobObject&) = delete; JobObject() { jobHandle = CreateJobObjectA(NULL, NULL); if (jobHandle == NULL) { throw std::runtime_error("Create job failed!"); } } HANDLE getHandle() { return jobHandle; } void assignProcess(const Process &p) { if (AssignProcessToJobObject(jobHandle, p.handle()) == 0) throw std::runtime_error("Failed to assgin process to job: "s + std::to_string(GetLastError())); } BOOL setInformation(const JobObjectInformation& i) { return SetInformationJobObject(jobHandle, i.getClass(), i.informationPtr(), i.length()); } ~JobObject() { CloseHandle(jobHandle); } private: HANDLE jobHandle{}; }; class CpuRateJobObjectInformation : public JobObjectInformation { public: CpuRateJobObjectInformation(int rate) { information.ControlFlags = JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP; if (rate <= 0 || rate > 100) throw std::runtime_error("Invalid argument"); information.CpuRate = rate * 100; } virtual JOBOBJECTINFOCLASS getClass() const override { return JOBOBJECTINFOCLASS::JobObjectCpuRateControlInformation; } virtual DWORD length() const override { return sizeof(information); } virtual LPVOID informationPtr() const override { return (LPVOID) &information; } private: JOBOBJECT_CPU_RATE_CONTROL_INFORMATION information{}; }; int main(int argc, const char **argv) { JobObject jobObject; CpuRateJobObjectInformation information{20}; jobObject.setInformation(information); ChildProcess childProcess{ "C:\\xiangqi.exe"}; jobObject.assignProcess(childProcess); childProcess.start(); childProcess.wait(); DWORD pid; std::cout << "Input PID:" << std::endl; std::cin >> pid; AttachProcess attachProcess{ pid }; try { jobObject.assignProcess(attachProcess); } catch (const std::exception& e) { std::cout << e.what(); } attachProcess.wait(); return 0; }
参考
打赏作者以资鼓励: