【问题标题】:How to limit the memory that an application can allocate如何限制应用程序可以分配的内存
【发布时间】:2017-08-01 04:55:46
【问题描述】:

我需要一种方法来限制服务可能分配的内存量,以防止服务使系统饥饿,类似于 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。不幸的是,如果我在 Flags 中传递 $00000000 以外的任何内容,SetProcessWorkingSetSizeEx 会失败并显示“代码 87。参数不正确”。

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

有什么想法或建议吗?

【问题讨论】:

  • 我认为您需要为此使用工作。
  • documentation 表示最小值。值必须为 20 * 页面大小(即 4K 页面大小的情况下为 81920)或更大,否则使用最小 20 * 页面大小。 (值以字节为单位。)
  • 在我看来,您的做法是错误的。如果您想编写一个不会使系统饿死的服务,请以不需要大量内存的方式编写它。考虑像 SQL 服务器这样的东西(根据问题):它使用大量内存的原因是它故意在内存中缓存尽可能多的数据以加快访问速度。当然,当超出物理内存时,它可以简单地依赖操作系统交换空间,但这会降低效率,因为操作系统不能使用索引表。因此,当您配置 SQL 内存使用时,您实际上只是在配置其内部缓存。
  • 你需要问自己的问题是为什么你需要这么多内存?您能否编写代码以更有效地使用内存?强制操作系统更快地换出应用程序使用的内存,或者在较低的栏中报告“内存不足”并不能真正解决根本问题。
  • PS:请注意,当您使用钝器以避免“饿死其他内存进程”时,您会面临以下风险:由于内存不足而为您自己的应用程序造成问题;或者在内核花费更多时间交换您的“体贴应用程序”时使其他进程的 IO 资源挨饿。所以无论你做什么:衡量和比较

标签: windows delphi memory 64-bit


【解决方案1】:

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、Windows XP SP3、Windows Server 2008、Windows Vista 和 Windows Server 2003:进程不得 已经被分配到工作;如果是,则该功能失败 ERROR_ACCESS_DENIED。从 Windows 8 开始,此行为发生了变化,并且 Windows 服务器 2012。

如果这是您的情况(即,您在旧 Windows 上收到 ERROR_ACCESS_DENIED),请检查进程是否已分配给作业(在这种情况下,您不走运),但还要确保它具有所需访问权限:PROCESS_SET_QUOTAPROCESS_TERMINATE

【讨论】:

    猜你喜欢
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 2013-11-20
    • 1970-01-01
    • 2012-11-21
    • 2011-08-27
    • 1970-01-01
    相关资源
    最近更新 更多