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; }