geelaw
2018-07-03 00:29:42 +08:00
是因为有程序泄露 USER 句柄。
每个会话理论上最多有 65536 个 USER 对象,每个 USER 对象在其会话中具有惟一的 USER 句柄(一个 uint16 )。默认情况下 Windows 允许一个进程建立最多 10000 个 USER 对象。几个 USER 对象的例子:菜单、窗口、光标、钩子、热键列表。
如果你打开 7 个程序,每个尝试创建 9360 个菜单对象并不删除它们,然后挂着不结束(显然,进程结束的时候它创建的 USER 对象会被系统回收),则当前桌面的 window manager 里将最多还能建立 16 个 USER 对象(实际上你一般无法全都成功,因为 Explorer.exe 里面也有很多 USER 对象)。Explorer 显示菜单的时候需要菜单对象,但是无法创建,就会有这种情况。
要解决该问题,最简单的方法是注销再登录,这样你会获得一个全新的会话。如果你知道哪个程序在泄露 USER 句柄,你可以关闭或重启这个程序(类似于补救内存泄露的方法)。
可以用 Sysinternals 的 Process Explorer 查看一个进程的 USER 对象数。
————————
读者习题:每个经典的 Win32 控件(按钮、复选框、单选按钮、进度条、文本框、标签、滚动条……)都是一个窗口,为什么 IE/Edge/Chrome 浏览复杂网页的时候不会耗尽 USER 对象?
答案:因为它们会自己绘制这些控件而不使用系统提供的窗口版本。但 IE 中的下拉列表仍然是窗口版本,因此如果一个网页具有一大堆下拉列表,可能会快速消耗 IE 的 USER 对象配额。