At first I couldn’t believe that such tool wasn’t readily available because I’ve seen dozens of posts on different forums asking how to do this, however… I guess nobody felt urged enough to actually write a command line app for this. Well, I did 😉 startwithmemlimit is a Win32 application, which can impose a hard limit on the maximum amount of virtual memory a process (and *by default* its children) can allocate. It uses Windows Jobs mechanism, available since Windows 2000. You can read a lot about it on Google and on MSDN, e.g. here, here and here. I prepared the binaries with 32- and 64-bit compilers provided with Windows SDK. You can also recompile them yourself if you’d like 😉 The code is BSD-licensed as always.
Usage:
startwithmemlimit32.exe command_line mem_limit_in_MB
startwithmemlimit64.exe command_line mem_limit_in_MB
DOWNLOAD:
startwithmemlimit.zip
Source code (BSD-licensed):
#define _WIN32_WINNT 0x05000
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class ScopedHandle {
public:
ScopedHandle(): m_Handle(NULL) {}
ScopedHandle(HANDLE h): m_Handle(h) {}
~ScopedHandle() { if (m_Handle != NULL) CloseHandle(m_Handle); }
ScopedHandle& operator=(HANDLE h) { m_Handle = h; return *this; }
bool operator==(HANDLE h) const { return (m_Handle == h); }
operator HANDLE() const { return m_Handle; }
private:
HANDLE m_Handle;
};
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Usage: startwithlimit command_line memory_limit_MBn");
return -1;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess(NULL, argv[1], NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
printf("Failed to create processn");
return -2;
}
ScopedHandle hProcess = pi.hProcess;
ScopedHandle hThread = pi.hThread;
ScopedHandle hJob = CreateJobObject(NULL, NULL);
if (hJob == NULL) {
printf("Failed to create jobn");
return -3;
}
JOBOBJECT_EXTENDED_LIMIT_INFORMATION eli;
if (!QueryInformationJobObject(hJob, JobObjectExtendedLimitInformation, &eli, sizeof(eli), NULL)) {
printf("Failed to query job infon");
return -4;
}
eli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
eli.JobMemoryLimit = _atoi64(argv[2]) * 1024 * 1024;
if (!SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &eli, sizeof(eli))) {
printf("Failed to set job infon");
return -5;
}
if (!AssignProcessToJobObject(hJob, hProcess)) {
printf("Failed to assign process to jobn");
return -6;
}
if (ResumeThread(hThread) == -1) {
printf("Failed to resume processn");
return -7;
}
return 0;
}
