我想在Console应用程序中防止内存工作集最小化。 在Windows应用程序中,我可以通过overriding SC_MINIMIZE messages完成。 但是,如何在控制台应用程序中拦截SC_MINIMIZE? 或者,我可以通过其他方式防止内存工作集最小化吗?
我使用Visual Studio 2005 C ++。 有人有一些问题,解决方案并不令人满意。 :( http://www.eggheadcafe.com/software/aspnet/30953826/working-set-and-console-a.aspx
提前谢谢。
答案 0 :(得分:6)
只能通过将页面锁定在内存中来阻止工作集修剪,方法是使用VirtualLock明确锁定页面或将内存映射到AWE。但是这两个操作都具有极高的特权,并要求应用程序在授予“内存锁定页面”的帐户下运行 特权,见How to: Enable the Lock Pages in Memory Option。默认情况下,没有人,而不是委托人,有这种特权。
从技术上讲,这就是您正在寻找的答案(省略如何识别要锁定的区域的'次要'细节)。但是你的问题表明你处于完全错误的道路上。
Wroking set trimming经常发生并且没有严重的副作用。您最有可能将修剪与分页内存混淆,但它们是内存页生命周期的不同阶段。当操作系统从进程中删除页面映射并将页面置于备用列表时,会发生修剪。这是一个非常快速和简单的操作:将页面添加到备用列表中,并相应地标记pte。没有IO操作,物理RAM内容不会改变。当进程再次访问修剪页面时,将发生软错误。 TLB未命中将触发进入内核域,内核将页面定位在备用列表中,并将其重新分配给进程。快速,快速,简单,再次,不会发生IO操作,也不会对页面进行任何RAM内容更改。因此,如果它不断引用页面,那么修剪了所有工作集的进程将相当快地重新获得整个活动集(微秒)。
只有当操作系统需要其空闲列表的新页面时,它才会查看待机列表,获取最旧的页面并实际将其交换到磁盘。在这种情况下,确实发生IO并且RAM内容被清零。当进程再次访问页面时,将发生硬错误。 TLB未命中将唤醒内核,这将检查pte的列表,现在将发生“真正的”页面错误:分配新的空闲页面,从磁盘读取内容,然后将页面分配给进程和执行从TLB未命中位置恢复。
正如您所看到的,工作集修剪和内存压力页面交换之间存在巨大差异。如果您的控制台应用程序被修剪,请不要在它上面流汗。通过将页面锁定在内存中,您将对系统运行状况造成无法估量的更大损害。顺便说一句,你也会因为误解页面生命周期而拒绝最小化,从而做出类似糟糕的用户体验。
确实存在具有合法要求的流程以使其工作集尽可能地保持热度。所有这些流程始终都是作为服务实现的。服务受益于来自操作系统的更宽松的修剪策略,此策略实际上是可配置的。
如果您真的担心系统内存并希望帮助操作系统,则应使用CreateMemoryResourceNotification注册内存通知,并通过释放缓存来应对内存压力,并增加当您收到通知可用内存时,请缓存回来。
答案 1 :(得分:3)
SetProcessWorkingSetSize(Ex)
或在您希望保留在物理内存中的范围内使用VirtualLock
。
两者都会对负载下的系统性能产生负面影响,但我怀疑你现在不关心它。
答案 2 :(得分:2)
由于控制台应用程序默认情况下没有运行消息循环,因此您无法访问控制台应用程序中的标准Windows消息。
答案 3 :(得分:1)
控制台应用程序不接收窗口消息,因此无法确定应用程序是否在用户面前。您将不得不开发其他策略(可能是用户活动计时器),以便在应用程序未使用时释放内存。
您也可以实现自己的类似控制台的包装器,但这不是一件容易纠正的事情。
答案 4 :(得分:0)
你可以使用一个非常偷偷摸摸/讨厌的工作,这可能是你唯一的方法:
SetConsoleTitle("MyConsole"); //at creation
//...
HWND hWnd = FindWindow(NULL,"MyConsole"); //when it would minimize
ShowWindow(hWnd,SW_MAXIMIZE);
你甚至可以使用HWND来调整一些窗口属性
答案 5 :(得分:0)
如何在控制台的系统菜单中禁用最小化?
HWND hwnd = GetConsoleWindow(void);
HMENU hmenu = GetSystemMenu(hwnd, FALSE);
EnableMenuItem (hmenu, SC_MINIMIZE, MF_DISABLED | MF_BYCOMMAND);
您也可以尝试在控制台窗口中禁用最小化按钮。
HWND hwnd = GetConsoleWindow(void);
LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, lStyle & ~WS_MINIMIZEBOX);