Windows进程CPU、内存等资源限制

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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

void main(int argc, char *argv[])
{
        unsigned long total = 0, count = 0, i = 0;

        while (1) {
                if (malloc(1024)) {
                        total += 1024;
                        count++;
                }
                if (!(++i &amp; 4095))
                        printf(&quot;alloc: %u size: %u bytes\n&quot;, count, total);
    }
}

无限制

在无限制的情况下,此进程会占满一个CPU核心,commit内存总占用达2G CPUStress unlimited

单一进程

在设定CPU上限16%及内存16M上限之后,结果如下: CPUStress single process 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 &lt;&lt; 20), // 16MB
        winjob.WithWriteClipboardLimit(),
}

const defaultCommand = &quot;.\\CPUStress.exe&quot;

多进程(双进程)

将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 &lt;&lt; 20), // 16MB
        winjob.WithWriteClipboardLimit(),
}

验证结果如下: CPUStress 2-processes CPUStress 2-processes

winjob example代码:

// +build windows

package main

import (
        &quot;encoding/json&quot;
        &quot;log&quot;
        &quot;os&quot;
        &quot;os/exec&quot;
        &quot;os/signal&quot;
        &quot;time&quot;

        &quot;golang.org/x/sys/windows&quot;

        &quot;github.com/kolesnikovae/go-winjob&quot;
)

var limits = []winjob.Limit{
        winjob.WithBreakawayOK(),
        winjob.WithKillOnJobClose(),
        winjob.WithActiveProcessLimit(3),
        winjob.WithProcessTimeLimit(10 * time.Second),
        winjob.WithCPUHardCapLimit(1600),    // 16%
        winjob.WithJobMemoryLimit(16 &lt;&lt; 20), // 16MB
        winjob.WithWriteClipboardLimit(),
}

const defaultCommand = &quot;.\\CPUStress.exe&quot;
const stressCommand  = &quot;.\\CPUStressX64.exe&quot;

func main() {
        job, err := winjob.Create(&quot;&quot;, limits...)
        if err != nil {
                log.Fatalf(&quot;Create: %v&quot;, err)
        }

        cmd := exec.Command(defaultCommand)
        cmd.Stderr = os.Stderr
        cmd.SysProcAttr = &amp;windows.SysProcAttr{
                CreationFlags: windows.CREATE_SUSPENDED,
        }
        if err := cmd.Start(); err != nil {
                log.Fatalf(&quot;Start: %v&quot;, err)
        }

        stress := exec.Command(stressCommand)
        stress.Stderr = os.Stderr
        stress.SysProcAttr = &amp;windows.SysProcAttr{
                CreationFlags: windows.CREATE_SUSPENDED,
        }
        if err := stress.Start(); err != nil {
                log.Fatalf(&quot;Start: %v&quot;, 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(&quot;Notify: %v&quot;, 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 &lt;-s:
                                log.Println(&quot;Closing job object&quot;)
                                if err := job.Close(); err != nil {
                                        log.Fatal(err)
                                }
                                log.Println(&quot;Closing subscription&quot;)
                                if err := subscription.Close(); err != nil {
                                        log.Fatal(err)
                                }
                                return

                        case n, ok := &lt;-c:
                                if ok {
                                        log.Printf(&quot;Notification: %#v\n&quot;, n)
                                } else if err := subscription.Err(); err != nil {
                                        log.Fatalf(&quot;Subscription: %v&quot;, err)
                                }

                        case &lt;-ticker.C:
                                if err := job.QueryCounters(&amp;counters); err != nil {
                                        log.Fatalf(&quot;QueryCounters: %v&quot;, err)
                                }
                                b, err := json.MarshalIndent(counters, &quot;&quot;, &quot;\t&quot;)
                                if err != nil {
                                        log.Fatal(err)
                                }
                                log.Printf(&quot;Counters: \n%s\n&quot;, b)
                        }
                }
        }()

        if err := job.Assign(cmd.Process); err != nil {
                log.Fatalf(&quot;Assign: %v&quot;, err)
        }
        if err := winjob.Resume(cmd); err != nil {
                log.Fatalf(&quot;Resume: %v&quot;, err)
        }

        if err := job.Assign(stress.Process); err != nil {
                log.Fatalf(&quot;Assign: %v&quot;, err)
        }
        if err := winjob.Resume(stress); err != nil {
                log.Fatalf(&quot;Resume: %v&quot;, err)
        }

        if err := cmd.Wait(); err != nil {
                log.Fatalf(&quot;Wait: %v&quot;, err)
        }
        if err := stress.Wait(); err != nil {
                log.Fatalf(&quot;Wait: %v&quot;, err)
        }

        // Wait for a signal.
        &lt;-done
}

参考链接

  1. 21 Best Ways to Limit the CPU Usage of a Process
  2. MSDN: Windows Process and Thread Functions
  3. MSDN: CPU Sets
  4. GetThreadTimes

191,991 条评论

  1. Эта медицинская заметка содержит сжатую информацию о новых находках и методах в области здравоохранения. Мы предлагаем читателям свежие данные о заболеваниях, профилактике и лечении. Наша цель — быстро и доступно донести важную информацию, которая поможет в повседневной жизни и понимании здоровья.
    Узнай первым! – [url=https://www.kremlinrus.ru/article/175/171439/]tver clinica plus[/url]

  2. Hello to all, how is all, I think every one is getting more from this web site, and your views
    are fastidious in favor of new viewers.

  3. Singapore’ѕ premier furniture store ɑnd expansive furniture showroom offerѕ the ultimate one-stⲟp shop
    experience for premium home furnishings ɑnd strategic furniture for HDB interior design. Wе deliver trendy ɑnd
    budget-friendly solutions ԝith exciting furniture promotions, bed frаme promotions
    and Singapore furniture sale оffers made for eѵery Singapore home.
    Ƭhe importance of furniture in interior design guides еvеry
    decision ԝhen buying furniture fߋr HDB interior design —
    fгom L-shaped sectional sofas аnd premium mattresses tо sturdy bed fгames,
    study ϲomputer desks ɑnd elegant coffee tables — ɑlways apply expert
    tips tο buy quality sofa bedd аnd quality coffee table for beѕt reѕults.
    Wһether you’re refreshing y᧐ur HDB living roօm furniture, bedroom furniture
    Singapore օr dining room furniture Singapore wіth tһe
    latest affordable HDB furniture Singapore, ߋur thoughtfully curated collections combine contemporary design,
    superior comfort ɑnd lasting durability tߋ create beautiful, functional living
    spaces tһat suit modern lifestyles аcross Singapore.

    Ꭺs the leading furniture store аnd large-scale furniture
    showroom іn Singapore, we provide the perfect one-ѕtop shopping experience fоr quality home furnishings and intelligent furniture fоr HDB interior
    design. Ꮃe offer contemporary аnd value-packed
    solutions packed ԝith furniture deals, sofa promotions ɑnd Singapore furniture sale
    οffers for every Singapore household.
    Mastering tһe impoгtance of furniture іn interior design whiⅼe buying furniture fоr
    HDB interior design helps ʏou select the perfect mix ߋf living гoom sofas, premium mattresses, storage
    bed fгames, practical study desks and elegant coffee tables — аlways follow оur proven tips tо buy quality bed
    frame, quality sofa bed аnd quality coffee table fοr flawless resսlts.
    Whеther yoᥙ ɑre revamping yⲟur living гoom furniture Singapore, bedroom furniture Singapore оr study space ԝith the latest
    affordable HDB furniture Singapore, ᧐ur thoughtfully selected
    collections deliver contemporary design, unmatched comfort ɑnd long-lasting
    durability fօr modern Singapore living spaces.

    Singapore’ѕ leading furniture store and expansive furniture showroom іs y᧐ur perfect оne-stop destination foг premium һome furnishings and thoughtful
    furniture fⲟr HDB interior design. Wе provide stylish
    and vɑlue-for-money solutions enriched ᴡith furniture оffers,
    sofa promotions ɑnd Singapore furniture sale ߋffers for every Singapore home.

    Tһe іmportance of furniture іn interior design Ƅecomes evеn clearer wһen buying furniture f᧐r HDB interior design — select space-efficient
    L-shaped sectional sofas, premium mattresses, queen bed fгames,
    ergonomic study desks and elegant cofee tables wһile folⅼoᴡing practical tips
    to buy quality bed fгame, quality sofa bed аnd quality coffee table.
    Ꮃhether you’rе refreshing youг HDB living roоm furniture, bedroom furniture Singapore ߋr dining room furniture Singapore with tһe ⅼatest furniture promotions, oᥙr thoughtfully curated collections merge contemporary design, superior comfort ɑnd lasting durability t᧐ create beautiful, functional living spaces tһat suit modern lifestyles ɑcross
    Singapore.

    Singapore’s toρ-rated furniture store ɑnd expansive furniture showroom іs yoսr ultimate one-stоp destination for
    premium mattresses. Ԝе provide stylish аnd affordable solutions enriched
    with furniture оffers, mattress deals аnd Singapore furniture sale offeгs for evеry Singapore
    һome. Thе іmportance of furniture in interior design Ƅecomes crystal ϲlear
    when buying furniture foг HDB interior design — choose quality mattresses
    ѕuch aѕ king size orthopedic mattresses, queen size cooling gel mattresses, single size firm
    latex mattresses аnd supportive hybrid mattresses that deliver unmatched sleep quality іn compact HDB bedrooms.
    Wһether ʏou’re refreshing ʏoսr bedroom furniture Singapore with tһe latest furniture
    promotions, our thoughtfully curated collections merge contemporary design, superior
    comfort ɑnd lasting durability tⲟ creɑtе beautiful,
    functional living spaces tһat suit modern lifestyles
    ɑcross Singapore.

    Feel free tⲟ surf tο my webpage: is europace а ɡood brand
    (https://anuntescu.ro/index.php?page=user&action=pub_profile&id=41697)

  4. It’s encouraging to see how many options there are beyond traditional Nursing Homes. Independent Living and Assisted Living can be very positive moves. I’ve been exploring success stories and resident testimonials on senior care .

  5. I like that you highlight family involvement and visiting policies. For my family, ease of visiting was a big factor. We used mapping and distance tools on senior care to narrow down suitable communities.

  6. I’ve read that smaller homes tend to better tailor activity programs to residents’ abilities. This seems essential for cognitive engagement. respite care has been a helpful source in learning what to look for.

  7. My aunt felt embarrassed asking for help in a big facility, but in a small home she formed real bonds with caregivers and felt comfortable getting support with personal care. assisted living reflects these benefits well.

  8. For those with arthritis or limited mobility, regular help with dressing and bathing is a game changer. Small assisted living settings tend to deliver that consistently. I found more info at senior care .

  9. It’s helpful to know that Independent Living can be a good stepping stone for seniors who want to downsize but are not ready for personal care services. I first considered that pathway after reading about it on dementia care .

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注