如何限制应用程序可以分配的内存

时间:2017-03-10 18:22:50

标签: windows delphi memory 64-bit

我需要一种方法来限制服务可以分配的内存量,以防止服务使系统挨饿,类似于SQL Server允许您设置"最大服务器内存的方式"。

我知道SetProcessWorkingSetSize并没有完全符合我的要求,但我试图让它按照我认为的方式行事。无论我使用什么值,我的测试应用程序的工作集都不受限制。此外,如果我之后立即调用GetProcessWorkingSetSize,则返回的值不是我之前指定的值。这是我的测试应用使用的代码:

var
  MinWorkingSet: SIZE_T;
  MaxWorkingSet: SIZE_T;
begin
  if not SetProcessWorkingSetSize(GetCurrentProcess(), 20, 12800 ) then
    RaiseLastOSError();

  if GetProcessWorkingSetSize(GetCurrentProcess(), MinWorkingSet, MaxWorkingSet) then
    ShowMessage(Format('%d'#13#10'%d', [MinWorkingSet, MaxWorkingSet]));

没有错误发生,但GetProcessWorkingSetSize返回的Min和Max值都是81,920。

我尝试在Flags参数中使用QUOTA_LIMITS_HARDWS_MAX_ENABLE($ 00000004)使用SetProcessWorkingSetSizeEx。不幸的是,SetProcessWorkingSetSizeEx失败了"代码87.参数不正确"如果我在Flags中传递除$ 00000000以外的任何东西。

我也一直在使用Job Objects来实现相同的目标。启动子进程时,我有使用Job Objects的内存限制。但是,我需要服务能够设置自己的内存限制,而不是依赖于"启动"服务去做。到目前为止,我还没有找到一种方法来让单个进程创建一个作业对象,然后将自己添加到作业对象中。这总是因访问被拒绝而失败。

有任何想法或建议吗?

1 个答案:

答案 0 :(得分:3)

SetProcessWorkingSetSize函数的文档说:

  

dwMinimumWorkingSetSize [in]

     

...

     

此参数必须大于   零但小于或等于最大工作集大小。该   默认大小为50页(例如,这是204,800字节   具有4K页面大小的系统)。如果该值大于零但是   少于20页,最小值设置为20页。

如果是4K页面大小,则强加的最小值为20 * 4096 = 81920字节,这是您看到的值。 值以字节为单位指定。

要实际限制服务进程的内存,我认为可以创建一个新作业(CreateJobObject),设置内存限制(SetInformationJobObject)并将当前进程分配给作业( AssignProcessToJobObject)在服务的启动例程中。

不幸的是,在8之前的Windows和Server 2012上,如果进程已经属于某个作业,这将不起作用:

  

Windows 7,Windows Server 2008 R2,带有SP3的Windows XP,Windows Server   2008,Windows Vista和Windows Server 2003:该过程绝对不能   已被分配到工作;如果是,则该功能失败   ERROR_ACCESS_DENIED。从Windows 8和Windows开始,此行为已更改   Windows Server 2012。

如果是这种情况(即你在旧版Windows上获得ERROR_ACCESS_DENIED),请检查该进程是否已分配给某个作业(在这种情况下,你运气不好)但也要确保它拥有所需的访问权限:PROCESS_SET_QUOTAPROCESS_TERMINATE