可能重复:
Is there any way to force the WorkingSet of a process to be 1GB in C++?
我们希望提前将.NET进程的WorkingSet增加到1GB,以避免页面错误。
有没有办法在.NET中执行此操作?
更新
不幸的是,即使我们调用SetProcessWorkingSetSizeEx,垃圾收集仍然会修改工作集,绕过MinWorkingSet(参见下图中的“自动GC.Collect()”)。 p>
在下图中,有没有办法将进程WorkingSet(绿线)锁定为1GB,以避免在为进程分配新内存时出现页面错误(红线)的峰值?
这很棒的原因是,每次发生页面错误时,它都会阻塞线程250us,这会严重影响应用程序性能。
更新
引自:“Windows via C / C ++,Fifth Edition,Jeffrey Richter(Wintellect)”
忽略单个进程对SetProcessWorkingSetSize的调用 除非该过程只是试图清空其工作集。设置 此限制,指定JOB_OBJECT_LIMIT_WORKINGSET标志 LimitFlags成员。
本书暗示设置WorkingSet的唯一方法是将进程分配给作业对象并设置JOB_OBJECT_LIMIT_WORKINGSET和MinimumWorkingSetSize。
更新
SetProcessWorkingSetSizeEx与软页面错误完全无关。它仅涉及硬页面错误,因为它可以防止当前WorkingSet中的内存被分页到硬盘驱动器。
更新
事实证明,增加WorkingSet的唯一方法是使用C ++编写的非常专业的CLR Host运行.NET(请参阅下面的答案)。
答案 0 :(得分:4)
要实现您想要的功能,您需要以最小1 GB(第二个参数)和QUOTA_LIMITS_HARDWS_MIN_ENABLE
作为第四个参数调用/ pinvoke SetWorkingSetSizeEx,以确保工作集大小不会低于最小值即使在系统的“高记忆压力”条件下也是如此。
系统行为还取决于调用者的权限,具体取决于操作系统版本等,您可能需要SE_INC_WORKING_SET_NAME
和/或SE_INC_BASE_PRIORITY_NAME
!
在“幕后”使用这些API的另一个(更好的)选项是您可以找到here的.NET包装器。
答案 1 :(得分:3)
如果您的问题是您的流程在低内存情况下过于激烈地修剪了WS,那么您可以通过调用SetProcessWorkingSetSize
或仅设置Process.CurrentProcess.MinWorkingSet
来处理它。
但是,您所展示的是,您的工作集正在被GC降低。这告诉我,真正发生的事情是GC正在释放组成你的WS的页面。如果是这种情况,则会出现地址空间问题而不是工作集问题,并且您无法进行系统调用以防止出现问题。理想情况下,您可以告诉GC不要将其内存返回给操作系统,但.NET没有这样的功能。
要解决地址空间问题,您必须重用已分配的对象。如果你的问题是大对象堆,那很可能是由于集合造成的。例如,不是创建新的数组/列表/字典,而是调用其Clear
方法并重用它。如果您的问题是字符串,那么您可以使用StringBuilder
来避开LOH。
如果您创建了许多类型的对象,请考虑创建一个可以回收的对象池。我从来没有做过这样的事情,但如果我要实现它,我会创建一个带有静态工厂方法的对象,该方法将对象拉出池并调用初始化程序而不是公共构造函数,并放置终结器它将它放回池中并使其中的任何引用无效。根据需要,池可能是ConcurrentBag<WeakReference<T>>
。
答案 2 :(得分:2)
我认为将流程分配给工作对象并设置JOB_OBJECT_LIMIT_WORKINGSET
and MinimumWorkingSetSize
可能会有效。
答案 3 :(得分:2)
我们可以找到增加.NET下进程的WorkingSet以减少软页面错误的唯一方法是在自定义CLR Host下运行整个.NET应用程序。这是一项非常重要的练习,需要大约800行自定义编写,相当密集的C ++代码。 C ++代码拦截了对Win32内存管理方法的.NET调用,改变了.NET运行时的行为,因此它不会像通常那样积极地释放内存。
这会导致应用程序启动时出现所有软页面错误,因此在正常的应用程序执行期间,.NET应用程序中的软页面错误数量几乎下降到零。
这意味着应用程序可能内存耗尽,但运行速度更快。换句话说,我们牺牲内存使用来提高实时性能。
答案 4 :(得分:1)
我认为这里存在一个误解:GC释放未使用的内存好。保持它只是为了在WS指标中看到更高的数字是没有用的......你不希望在WS中使用未使用的内存。您正在针对错误的指标进行优化。
页面错误的数量没有那么有意义,因为存在软故障和硬故障。从磁盘读取硬故障。在大多数情况下,软故障毫无意义。它们是操作系统的实现细节。例如,对于每个新分配的页面,您都会触摸软故障。
以下是一些证据表明您的红色图表没有显示硬故障:最后它显示大约500 /秒。您的磁盘无法提供500 IOP,因此不会出现硬故障。
您可能只想测量(并减少)硬故障。只有硬故障才能以有意义的方式影响性能。
此外,设置WS限制不会影响GC的功能。 GC不是操作系统组件。是一个用户模式库。它与操作系统决定用作工作集的内容无关。因此,您无法通过设置WS限制来使GC不释放内存。
那么为什么在GC运行时WS会缩小?因为GC 删除了一些内存。设置一些WS限制不能阻止删除内存。
在评论中建议GC可能会调用某些API来缩小工作集。我看不出任何理由为什么会这样做。为什么GC会强制页面退出流程?请记住:WS和分配的页面不一样(完全没有!)。 GC可能会释放内存。它不会强制WS收缩。这有什么用途?