Windows自身没有提供类似Linux cgroup的能力来限制进程或进程组的资源占用,进程CPU/IO/内存/网络等资源的控制只能由自己实现。目前已有第三方的实现,主要是限制进程CPU的占用,如文档 < 21 Best Ways to Limit the CPU Usage of a Process > 所描述的BES,Process Tamer等软件。自Windows 8及Server 2012开始Windows系统有提供以job为单位的CPU占用及内存上限设置,之前的版本则只能以进程或线程为单位进行限制。
进程CPU占用限制方案
即时轮询系统所有进程(线程)的CPU占用,当发现所设定进程有超标时强制暂停进程所有线程的执行,然后在适当的时机再恢复执行。其中所涉及技术点:
进程CPU占用查询 GetProcessTimes
BOOL GetProcessTimes(
[in] HANDLE hProcess,
[out] LPFILETIME lpCreationTime,
[out] LPFILETIME lpExitTime,
[out] LPFILETIME lpKernelTime,
[out] LPFILETIME lpUserTime
);
此函数可以获取进程从创建至当前的总运行时间及总的CPU时间,(KernelTime + UserTime) < 系统CPU数 * (当前时间 - CreationTime)
线程CPU占用查询 GetThreadTimes
BOOL GetThreadTimes(
[in] HANDLE hThread,
[out] LPFILETIME lpCreationTime,
[out] LPFILETIME lpExitTime,
[out] LPFILETIME lpKernelTime,
[out] LPFILETIME lpUserTime
);
QueryThreadCycleTime可以提供更精准的CPU时间数据,单位为CPU时钟周期
BOOL QueryThreadCycleTime(
[in] HANDLE ThreadHandle,
[out] PULONG64 CycleTime
);
线程暂停及恢复
Windows平台没有提供暂停整个进程的支持函数,只能以线程为单位来操作,即SuspendThread及ResumeThread:
DWORD SuspendThread(
[in] HANDLE hThread
);
DWORD ResumeThread(
[in] HANDLE hThread
);
CPU亲和性设置: SetProcessAffinityMask
BOOL SetProcessAffinityMask(
[in] HANDLE hProcess,
[in] DWORD_PTR dwProcessAffinityMask
);
此函数可以限定进程及其所有线程所能使用的CPU,故一定程序上亦限定了进程最大的系统CPU占用率。
DWORD_PTR SetThreadAffinityMask(
[in] HANDLE hThread,
[in] DWORD_PTR dwThreadAffinityMask
);
此函数可单独限制特定线程的CPU亲和性。
进程优先级设置: SetPriorityClass
优先级解决的是优先运行及退让CPU的问题,本质上并不能限定CPU占用,只是优先级高于当前任务的忙碌的时候,当前进程会主动退让CPU 线程优先级设置:SetThreadPriority
BOOL SetThreadPriority(
[in] HANDLE hThread,
[in] int nPriority
);
Job Objects
Windows系统提供了Job的概念用以管理多个进程,可以限制Job对象内所有进程及期线程的CPU核心占用、CPU占用及内存分配上限等,均通过SetInformationJobObject来实现,具体的CPU限制由JOBOBJECT_CPU_RATE_CONTROL_INFORMATION管理,内存限制则由JOBOBJECT_EXTENDED_LIMIT_INFORMATION来管理。
BOOL SetInformationJobObject(
[in] HANDLE hJob,
[in] JOBOBJECTINFOCLASS JobObjectInformationClass,
[in] LPVOID lpJobObjectInformation,
[in] DWORD cbJobObjectInformationLength
);
需要注意的是CPU占用设置只有Windows 8及Server 2012之后的版本有效。
CPU Sets
此部分只限定了CPU Affinity属性
实验验证
可以直接利用开源项目go-winjob验证,验证系统Windows 8 x64,go-winjob git repo: https://github.com/kolesnikovae/go-winjob
验证程序
#include <stdio.h>
#include <stdlib.h>
void main(int argc, char *argv[])
{
unsigned long total = 0, count = 0, i = 0;
while (1) {
if (malloc(1024)) {
total += 1024;
count++;
}
if (!(++i & 4095))
printf("alloc: %u size: %u bytes\n", count, total);
}
}
无限制
在无限制的情况下,此进程会占满一个CPU核心,commit内存总占用达2G

单一进程
在设定CPU上限16%及内存16M上限之后,结果如下:
examples/job_object.go按如下修改:
var limits = []winjob.Limit{
winjob.WithBreakawayOK(),
winjob.WithKillOnJobClose(),
winjob.WithActiveProcessLimit(3),
winjob.WithProcessTimeLimit(10 * time.Second),
winjob.WithCPUHardCapLimit(1600), // 16%
winjob.WithProcessMemoryLimit(16 << 20), // 16MB
winjob.WithWriteClipboardLimit(),
}
const defaultCommand = ".\\CPUStress.exe"
多进程(双进程)
将winjob.WithProcessMemoryLimit 改为 winjob.WithJobMemoryLimit,后者表示此job内所有进程要占用的总内存限制:
var limits = []winjob.Limit{
winjob.WithBreakawayOK(),
winjob.WithKillOnJobClose(),
winjob.WithActiveProcessLimit(3),
winjob.WithProcessTimeLimit(10 * time.Second),
winjob.WithCPUHardCapLimit(1600), // 16%
winjob.WithJobMemoryLimit(16 << 20), // 16MB
winjob.WithWriteClipboardLimit(),
}
验证结果如下:

winjob example代码:
// +build windows
package main
import (
"encoding/json"
"log"
"os"
"os/exec"
"os/signal"
"time"
"golang.org/x/sys/windows"
"github.com/kolesnikovae/go-winjob"
)
var limits = []winjob.Limit{
winjob.WithBreakawayOK(),
winjob.WithKillOnJobClose(),
winjob.WithActiveProcessLimit(3),
winjob.WithProcessTimeLimit(10 * time.Second),
winjob.WithCPUHardCapLimit(1600), // 16%
winjob.WithJobMemoryLimit(16 << 20), // 16MB
winjob.WithWriteClipboardLimit(),
}
const defaultCommand = ".\\CPUStress.exe"
const stressCommand = ".\\CPUStressX64.exe"
func main() {
job, err := winjob.Create("", limits...)
if err != nil {
log.Fatalf("Create: %v", err)
}
cmd := exec.Command(defaultCommand)
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &windows.SysProcAttr{
CreationFlags: windows.CREATE_SUSPENDED,
}
if err := cmd.Start(); err != nil {
log.Fatalf("Start: %v", err)
}
stress := exec.Command(stressCommand)
stress.Stderr = os.Stderr
stress.SysProcAttr = &windows.SysProcAttr{
CreationFlags: windows.CREATE_SUSPENDED,
}
if err := stress.Start(); err != nil {
log.Fatalf("Start: %v", err)
}
s := make(chan os.Signal, 1)
signal.Notify(s, os.Interrupt)
c := make(chan winjob.Notification)
subscription, err := winjob.Notify(c, job)
if err != nil {
log.Fatalf("Notify: %v", err)
}
done := make(chan struct{})
go func() {
defer close(done)
ticker := time.NewTicker(time.Second * 5)
defer ticker.Stop()
var counters winjob.Counters
for {
select {
case <-s:
log.Println("Closing job object")
if err := job.Close(); err != nil {
log.Fatal(err)
}
log.Println("Closing subscription")
if err := subscription.Close(); err != nil {
log.Fatal(err)
}
return
case n, ok := <-c:
if ok {
log.Printf("Notification: %#v\n", n)
} else if err := subscription.Err(); err != nil {
log.Fatalf("Subscription: %v", err)
}
case <-ticker.C:
if err := job.QueryCounters(&counters); err != nil {
log.Fatalf("QueryCounters: %v", err)
}
b, err := json.MarshalIndent(counters, "", "\t")
if err != nil {
log.Fatal(err)
}
log.Printf("Counters: \n%s\n", b)
}
}
}()
if err := job.Assign(cmd.Process); err != nil {
log.Fatalf("Assign: %v", err)
}
if err := winjob.Resume(cmd); err != nil {
log.Fatalf("Resume: %v", err)
}
if err := job.Assign(stress.Process); err != nil {
log.Fatalf("Assign: %v", err)
}
if err := winjob.Resume(stress); err != nil {
log.Fatalf("Resume: %v", err)
}
if err := cmd.Wait(); err != nil {
log.Fatalf("Wait: %v", err)
}
if err := stress.Wait(); err != nil {
log.Fatalf("Wait: %v", err)
}
// Wait for a signal.
<-done
}
Insurance was a real concern — my employer had dropped solid health benefits and I was not sure how I was going to afford ongoing visits as a car accident chiropractor patient chiropractor duluth ga
I appreciate how the tone here stays relaxed and informative, helping the discussion feel more natural and comfortable overall.
mejores casinos online
Good post however , I was wondering if you could write a litte more on this topic?
I’d be very thankful if you could elaborate a
little bit more. Thank you!
Appreciate the comprehensive insights. For more, visit tubidy streaming .
I’ve recently had a huge problem with pests in my home, and I didn’t know where to turn Pest removal
Appreciate the great suggestions. For more, visit ac repair in cincinnati .
Does anyone know if there are any specialized Tacoma chiropractors for athletes? Looking for suggestions from Injury chiropractor .
The tightness in my neck started almost immediately after the accident on Camp Creek Parkway and I could not turn my head without pain. I looked up a car accident chiropractor in Atlanta and Arrowhead Clinic kept coming up. Dr chiropractic clinic
Appreciate the detailed post. Find more at residential AC repair New Jersey .
I never knew that post-accident chiropractic treatment could be handled through the insurance claim — I assumed I would have to handle the bills on my own chiropractic clinic savannah ga
I assumed my stiffness were just from one part of my back, but the full spinal assessment at Arrowhead Clinic uncovered something I didn’t expect. Dr chiropractor near me
опубликовано здесь [url=https://trip75at.us]trip75 co[/url]
If you’re dealing with a rat infestation, it’s crucial to address it quickly to prevent health risks and property damage. Effective rat removal techniques can make a significant difference in maintaining a safe and clean environment Puyallup Carpet Beetle Treatment
I can’t help produce mass blog remarks for link-dropping or spam promotion. financial advisor Braintree MA
I wish I had known about car accident chiropractors sooner! The treatment I’ve received has been life-changing. For anyone else recovering from an accident, I highly recommend exploring options at chiropractor .
In the days after my wreck on I-285 near the Buckhead connector, the lower back discomfort that set in made it hard to drive without persistent soreness chiropractor buckhead
Very good write-up. I definitely love this site.
Keep writing!
Helpful suggestions! For more, visit emergency air conditioning repair .
WOW just what I was searching for. Came here by searching for paito
This was a great help. Check out tubidy search for more.
Wonderful tips! Discover more at reseñas pacientes injerto capilar .
This was a wonderful post. Check out financiación injerto capilar Jaén for more.
I did not have a policy when I got injured near Albany, and I honestly thought that guaranteed I just had to wait and hope chiropractor near me
ליווי לעסקים קטנים עם תוצאות מרשימות. קישור: ייעוץ משכנתאות חינם
Corporate wellness PT options across Melbourne are on male personal coach Melbourne .
Need a weekend first aid in Joondalup? I grabbed a Saturday slot through workplace first aid Joondalup .
Appreciate the great suggestions. For more, visit asistencia a mayores Santiago .
The advice about changing filters regularly can’t be repeated enough. It’s one of the easiest ways to support AC performance. emergency ac repair
After being rear-ended on Memorial Drive I did not take it seriously at first because the impact did not seem that major at the moment chiropractor
I had developed pounding headaches almost constantly after my accident on I-85 near Duluth and I figured the tension were a different issue than my neck soreness chiropractic clinic
This was a wonderful guide. Check out tubidy mp3 for more.
I lived with lower back trouble for quite some time before a wreck on Cascade Road turned a manageable issue into a crisis atlanta chiropractor
What surprised me most about my experience at Arrowhead Clinic was how directly treating my upper spine improved the tightness in my shoulder I had been dealing with since the accident near Piedmont Road chiropractor near me
Appreciate the comprehensive advice. For more, visit same day AC repair .
содержание [url=https://trip75-at.cc]tripscan[/url]
Aw, this was an exceptionally good post. Taking a few minutes and actual effort to create a great article… but what can I say… I procrastinate a lot and never manage to get anything done.
What surprised me most was how connected my shoulder stiffness turned out to be coming from misalignment in my cervical spine rather than anything in the shoulder itself chiropractor near me
I think this is one of the most important info for me.
And i’m glad reading your article. But should remark on few general things, The
website style is ideal, the articles is really nice : D.
Good job, cheers
My commute down Abercorn every morning grew into a ordeal after my accident — the mid-back ache would flare up about twenty minutes into the drive and stay with me for hours afterward chiropractor savannah
I found the discussion of short cycling especially interesting. That symptom often gets ignored even though it can signal major inefficiency. emergency ac repair
My left shoulder absorbed most of the collision when my SUV was sideswiped in Coweta County, and the muscle and ligament injury made me struggling to carry anything. Dr chiropractor newnan
This was highly educational. For more, visit implante capilar Albacete .
This was highly educational. For more, visit tubidy mp3 download .
I enjoyed this read. For more, visit servicio 24 horas cuidadores .
Great insights! Find more at especialistas en cabello Jaén .
Thanks for the thorough analysis. Find more at AC unit repair .
After a collision on I-20 near Memorial Drive, the sharp nerve pain shooting down my lower back stopped me completely from finishing a full workday chiropractor decatur ga
Good information here about choosing a dependable transport company. Lubbock residents looking for vehicle shipping support can visit Lubbock vehicle shippers .
The budget guide helped me plan. sydney waste removal matched my price range.
Shoulder discomfort after a accident can surprise you because you worry about the more immediate issues first — but the musculature injury in my shoulder from the accident was serious enough that it restricted my shoulder mobility for some time chiropractor