有没有办法将进程的当前WorkingSet扩展到1GB?

可能重复:
有没有办法强制进程的WorkingSet在C ++中为1GB?

我们希望提前将.NET进程的WorkingSet增加到1GB,以避免页面错误。

有没有办法在.NET中执行此操作?

更新

不幸的是,看起来即使我们调用SetProcessWorkingSetSizeEx ,垃圾收集仍会修改工作集,绕过MinWorkingSet(参见下图中的“自动GC.Collect()”)。

在下图中,有没有办法将进程WorkingSet(绿线)锁定为1GB,以避免在为进程分配新内存时出现的页面错误(红线)出现峰值?

这很棒的原因是,每次发生页面错误时,它都会阻塞250us的线程,这会严重影响应用程序性能。

在此处输入图像描述

更新

引用自:“Windows via C / C ++,Fifth Edition,Jeffrey Richter(Wintellect)”

除非进程只是尝试清空其工作集,否则将忽略单个进程对SetProcessWorkingSetSize的调用。 要设置此限制,请在LimitFlags成员中指定JOB_OBJECT_LIMIT_WORKINGSET标志。

本书暗示设置WorkingSet的唯一方法是将进程分配给作业对象并设置JOB_OBJECT_LIMIT_WORKINGSET和MinimumWorkingSetSize。

更新

SetProcessWorkingSetSizeEx与软页面错误完全无关。 它仅指硬页面错误,因为它可以防止当前WorkingSet中的内存被分页到硬盘驱动器。

更新

事实certificate,增加WorkingSet的唯一方法是使用用C ++编写的极其专业的CLR主机来运行.NET(请参阅下面的答案)。

为了达到你想要的效果,你需要调用/ pinvoke SetWorkingSetSizeEx ,最小值为1 GB(第二个参数), QUOTA_LIMITS_HARDWS_MIN_ENABLE作为第四个参数,这样可以确保工作集大小不会低于最小值,即使在“高内存压力”条件下也是如此。系统。

系统行为还取决于调用者的权限,具体取决于操作系统版本等,您可能需要SE_INC_WORKING_SET_NAME和/或SE_INC_BASE_PRIORITY_NAME

在幕后使用这些API的另一个(更好的)选项是你可以在这里找到的.NET包装器。

如果您的问题是您的进程在低内存情况下使其WS调整过于激烈,您可以通过调用SetProcessWorkingSetSize或仅设置Process.CurrentProcess.MinWorkingSet来处理它。

但是,你所展示的是,你的工作集正在被GC降低。 这告诉我,真正发生的事情是GC正在释放组成你的WS的页面。 如果是这种情况,则会出现地址空间问题而不是工作集问题,并且您无法进行系统调用来阻止它。 理想情况下,您可以告诉GC不要将其内存返回给操作系统,但.NET没有这样的function。

要解决地址空间问题,您必须重用已分配的对象。 如果你的问题是大对象堆,那很可能是由于集合。 例如,不是创建新的数组/列表/字典,而是调用其Clear方法并重用它。 如果您的问题是字符串,您可能可以使用StringBuilder来避开LOH。

如果您创建了许多类型的对象,请考虑创建一个可以回收的对象池。 我从来没有做过这样的事情,但如果我要实现它,我会创建一个带有静态工厂方法的对象,该方法将对象拉出池并调用初始化器而不是公共构造器,并在其上放置一个终结器将它放回池中并将其中的任何引用置空。 根据需要,池可能是ConcurrentBag>

我认为将进程分配给作业对象并设置JOB_OBJECT_LIMIT_WORKINGSETMinimumWorkingSetSize可能会起作用。

我们可以找到增加.NET下进程的WorkingSet以减少软页面错误的唯一方法是在自定义CLR主机下运行整个.NET应用程序。 这是一项非常重要的练习,需要大约800行自定义编写,相当密集的C ++代码。 C ++代码拦截了对Win32内存管理方法的.NET调用,改变了.NET运行时的行为,因此它不会像通常那样积极地释放内存。

这会在应用程序启动时产生所有软页面错误,因此在正常的应用程序执行期间,.NET应用程序中的软页面错误数量几乎下降到零。

这意味着应用程序可能内存耗尽,但运行速度更快。 换句话说,我们牺牲内存使用来提高实时性能。

我认为这里有一个误解:GC释放未使用的内存是好的 。 保持它只是为了在WS度量中看到更高的数字是没有用的……你不希望 WS中有未使用的内存。 您正在针对错误的指标进行优化。

由于存在软故障和硬故障,因此页面错误的数量并不重要。 从磁盘读取硬故障。 在大多数情况下,软故障毫无意义。 它们是操作系统的实现细节。 例如,对于每个新分配的页面,您都会触摸发生软故障。

以下是一些证据表明您的红色图表没有出现硬故障:最后它显示大约500 /秒。 您的磁盘无法提供500 IOP,因此不会出现硬故障。

您可能只想测量(和减少)硬故障。 只有硬故障才能以有意义的方式影响性能。

此外,设置WS限制不会影响GC的function。 GC不是操作系统组件。 是一个用户模式库。 它与操作系统决定用作工作集的内容无关。 因此,您无法通过设置WS限制来使GC不释放内存。

那么为什么当GC运行时WS会缩小? 因为GC 删除了一些内存。 设置一些WS限制不能阻止删除内存。

在评论中建议GC本身可以调用一些API来缩小工作集。 我看不出任何理由为什么会这样做。 为什么GC会强制页面退出流程? 请记住:WS和分配的页面不一样(完全没有!)。 GC可能会释放内存。 它不会强制WS缩小。 这有什么用途?