CLI tool
lowleveldesign/process-governor avatar
lowleveldesign/process-governor

Process Governor: putting limits on Windows processes with job objects

This application allows you to put various limits on Windows processes.

824 stars74 forksC#MIT

At a glance

What is it?
Process Governor is a small Windows tool that wraps a process in a job object so you can cap its memory, pin its CPU, rate limit it or stop it after a time. It is a developer tool for testing and experimentation rather than a long-running policy enforcer, and its service mode is still beta.
Who is it for?
Process Governor is the right tool for reproducing memory pressure, throttling a build or test process, or experimenting with CPU affinity on Windows, and it is the wrong tool for enforcing limits on production workloads, since its service mode is described as beta and its job objects are per-session rather than system wide.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 106 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Job objects are the mechanism behind every limit

Windows already has the primitive Process Governor uses. A job object is a kernel object that groups processes and carries limits and restrictions for the group, and the tool wraps a process in one on your behalf. That is the whole design: there is no injection, no hooking and no rewriting of the target binary. The limit is applied by the operating system because the process is in a job, and the process itself does not need to cooperate.

The audience is a developer on Windows who needs to reproduce a constrained environment. The documentation gives the clearest example: you can cap the memory a process commits so that a leaking .NET application, including a web application, throws OutOfMemoryException sooner, which turns a slow memory leak into a fast failing test. The same mechanism throttles CPU, pins a process to specific cores, and caps how long it may run.

The tool is written in C# and the repository is laid out like a normal .NET solution, with the main project, a procgov-lib library project, and a separate AOT test project. The practical appeal is that the limits are external to the process, so you can apply them to something already running, which is what makes it useful for third-party binaries you did not build.

Three run modes, and the service one is beta

The tool has three modes, and they are worth separating because they behave differently.

The command-line application mode is the default. You launch procgov from a command prompt, and it either starts a new process or attaches to a running one, with the limits applied as it goes.

The monitor mode appears when you use the --job-name switch. In that case procgov launches a second instance of itself whose command line contains the --monitor switch, and that second instance's job is to monitor the jobs created by procgov. The documentation constrains it: there should be at most one job monitor instance per Windows session, and the monitor should exit right after the last process in the monitored jobs terminates.

The service mode is marked beta, with a caution in the documentation and an invitation to report errors. Using the --install switch persists application settings in the registry and creates a Windows service named ProcessGovernor. By default it uses the SYSTEM account and the %ProgramFiles%\ProcessGovernor folder as the service base path, and you can change those with --service-path, --service-username and --service-password. Installing for another application adds data to the registry and reuses the existing service, which picks up the updated configuration after a short time. The service watches starting processes and applies the limits defined at install time. Removal has two levels: --uninstall removes the service when the last saved configuration goes, and --uninstall-all removes all saved procgov data along with the service.

Attaching to a running process, and passing arguments through

Two things are worth knowing before the first run. First, limits apply to a process that already exists as well as to one you are starting, which is the more useful case when you want to constrain something you did not start. The --pid switch, with the short form -p, targets a running process:

bash
procgov.exe --maxmem 40M --pid 1234

Second, when you start a new process you pass the image path as an argument to procgov, and when the target program has parameters of its own you separate the two sets with --, so procgov does not try to interpret them:

bash
procgov.exe -m 100M -- test.exe -arg1 -arg2=val2 arg3

The same -p switch can be repeated to put several processes into one job object and give them all the same limits:

bash
procgov.exe --maxmem 100M -p 1234 -p 1235 -p 1236

That is worth pausing on, because it is the difference between a per-process tool and a grouping tool. Once processes share a job, the limits apply to the group, and the documentation is explicit that a process cannot be assigned to a different procgov job afterwards: it must be either in the same job or unassigned.

Version 4.0 made anonymous jobs unchangeable

This is the sharpest edge in the tool, and it is a behavioural change rather than a bug.

Starting from version 4.0, procgov job objects are anonymous and they cannot be updated. Running procgov again for the same process creates a new job object, which means the second invocation does not tighten the first one, it starts over. If you want to change limits you have already applied, you need the --job-name switch, which creates a named job object instead. You then run procgov again with the same job name, the new limits and the target process ids, and procgov overwrites the previous limits with the new ones.

The documentation walks through it in two commands:

bash
# We set a CPU limit on a process 1234
procgov.exe --job-name job1234 --nowait -c 2 -p 1234

# Then we run procgov again with the new CPU limit - procgov will update the existing job object
procgov.exe  --job-name job1234 --nowait -c 4 -p 1234

The --nowait switch lets procgov return instead of waiting for the process to exit, which is what you want when the constrained process is long lived and you intend to adjust it later. The trade is that the named-job workflow is more moving parts than the anonymous one, and it ties you to a single procgov job per process.

Committed memory is not working set, and the difference matters

The memory limits are where the tool earns its keep, and the documentation is careful about which quantity is being capped.

The --maxmem switch, short form -m, limits the memory committed by a process, and on Windows committed memory is all the private memory the process uses. The example applies it both to a process being started and to one already running:

bash
procgov.exe -m 100M -c 2 notepad.exe

procgov.exe -m 120M -p 1234

Because the cap applies to private memory rather than to the shared pages the process maps, a process can fail with OutOfMemoryException while the machine still has free physical memory. That is the intended behaviour for a leak test, and it is also the reason the same limit behaves differently on different applications.

The --maxws and --minws switches are the other pair, and they control the maximum and minimum working set sizes, which is physical memory usage. These need the SeIncreaseBasePriorityPrivilege privilege, and the documentation links to issue 69 for the details. In other words, one class of memory limit works from an ordinary account and the other requires a privilege the account has to hold, which is a difference that will bite you in a locked-down environment before it bites you in a test run.

Beyond memory: affinity, CPU rate, priority and a deep freeze

The constraint list in the documentation is longer than memory and CPU affinity, and a few of the entries are unusual enough to be worth naming.

Alongside the affinity and rate limits there are two time based limits: one on the execution time of the process measured as clock time, and one on the user-mode execution time specifically. The distinction matters for a test that wants to bound work rather than wall clock waiting, since a process blocked on I/O consumes clock time without consuming user-mode time.

Then there is the set of other options: setting the priority class, setting the efficiency mode, setting additional environment variables for the target process, and enabling process privileges. The environment variable option is a quiet one, since it lets a test set variables for a program you did not write without touching its configuration.

And there is deep-freeze processes, which the documentation labels experimental. A frozen process stops consuming CPU while it waits, which is a different mechanism entirely from the affinity and rate limits, and it is the one entry in the list that is not part of a stable set. Treat it as something to evaluate, not something to depend on.

Packaging for Windows and the shape of the repository

The distribution story is standard for a Windows utility. Binaries are published on the release page, and the two package managers are the usual pair:

bash
choco install procgov
# or
winget install procgov

The repository carries the packaging metadata for both, with a .choco directory and a .winget directory at the top level, and a winget-publish.ps1 script for the publishing step. There is also a procgov.wprp file, which is a Windows Performance Recorder profile, so the tool ships with the means to record what a constrained process actually did.

The solution contains procgov for the main application, procgov-lib for the library part, and procgov-tests-aot, a test project targeting ahead-of-time compilation, alongside the docs directory. The releases are versioned with the build number attached: v4.1 shipped as 4.1.26190 on 2026-07-08, v4.0 as 4.0.26155 on 2026-06-04, and v3.2 as 3.2.25275 on 2025-10-02. The last push to the repository was on 2026-07-08, the day of the v4.1 release.

The licence is MIT, and the README is the only user documentation in the repository, with a table of contents that runs to a reporting issues section rather than a version history or a compatibility matrix.

Editorial conclusion

Process Governor is the right tool for reproducing memory pressure, throttling a build or test process, or experimenting with CPU affinity on Windows, and it is the wrong tool for enforcing limits on production workloads, since its service mode is described as beta and its job objects are per-session rather than system wide. Verify first whether your workflow needs limits you can change after the fact, because since version 4.0 an anonymous job object cannot be updated and only a named job created with --job-name can be rewritten, and check that the account you run under holds SeIncreaseBasePriorityPrivilege if you intend to use --maxws or --minws.

Frequently asked questions

How do I install Process Governor on Windows?

Download the binaries from the release page, or install the package with choco install procgov, or with winget install procgov. The default run mode is the command-line application mode, where you launch procgov to start a new process or attach to a running one.

How do I limit the memory of a process that is already running?

Use the --pid switch, or -p, with the --maxmem switch. For example procgov.exe --maxmem 40M --pid 1234 applies a 40 megabyte cap to committed memory of the running process 1234. The cap is on committed private memory, so the process can fail with OutOfMemoryException while physical memory is still free.

Can I change limits on a process after I have applied them?

Not with an anonymous job. Since version 4.0, job objects are anonymous and cannot be updated, so running procgov again creates a new job object. To update limits you must use the --job-name switch to create a named job and then run procgov again with the same job name and the new limits.

What does the Process Governor service mode do and is it ready to use?

It is described as beta. The --install switch saves the settings in the registry and creates a Windows service named ProcessGovernor, by default running as SYSTEM from %ProgramFiles%\ProcessGovernor, and the service then monitors starting processes and applies the limits defined at installation. The --uninstall and --uninstall-all switches remove it.

What licence is Process Governor released under?

MIT, with the licence text in the LICENSE file at the root of the repository.

Official sources

  1. Issues
  2. License: MIT
  3. lowleveldesign/process-governor on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lowleveldesign-process-governor.svg)](https://hysenlabs.com/projects/lowleveldesign-process-governor)

Was this useful?