调试桌面堆耗尽

时间:2017-09-05 09:10:31

标签: heap

我现在支持的产品似乎消耗了大量的桌面堆。二进制文件大多是.net,并且都将会话0作为非交互式进程运行(它们都是已安装的Windows服务的子进程)。所以,据我所知,他们不应该使用任何桌面堆。

我们在系统日志中有几个环境报告事件ID 243,然后间歇性地在应用程序日志中记录事件ID 1000;应用程序日志中的异常始终为0xc0000142。最终,我们的一项服务也会因一些神秘(无用)的消息而崩溃。不幸的是,我们从来没有能够捕获异常,但这些似乎都是桌面堆耗尽的非常明确的指标。

我正在试图找出消耗这么多桌面堆的东西,以便我可以追踪原因。但这是我陷入困境的地方。最初我计划安装Desktop Heap Monitor,但是在尝试使用它之后,我意识到它在XP之后的任何东西都不受支持。我在某处读过Process Explorer应该能够给我相同的信息,所以我们一直在监视PE中的以下对象:

  1. 处理计数
  2. GDI对象
  3. USER Objects
  4. 报告事件243时的“处理计数”值与未发生问题的几天前相比,或者甚至在启动过程的几分钟内没有显着差异。并且GDI和USER对象都是零。所以,我真的不知道究竟可能耗尽桌面堆,或者就此而言,如何进一步调试它。我在某处看到WeakEventManager可能导致这个问题,但我们似乎并没有使用它。

    我在google和SO上都搜索过这个东西,到目前为止我还没有找到任何东西。我真正想要的是确定哪个进程正在耗尽堆,或者至少哪个进程耗费最多。如果有人对如何做到这一点有任何指示,我真的很感激。

1 个答案:

答案 0 :(得分:5)

一个旧线程,但我想我会回来,因为将来有人会遇到这个问题。经过一些调试后,我们确定了哪些进程导致了问题。我决定将WinDbg附加到进程并在CreateWindowEx和NtDestroyWindow上设置一个bp。果然,CreateWindowEx确实被调用来创建一个隐藏的窗口;从堆栈上的params我能够获得该窗口的类(它总是相同的),这有助于进一步降低范围。

随着时间的推移,我开始注意到对NtDestroyWindow的调用次数少于对CreateWindowEx的调用次数。所以我放下了callstack,看看是什么创建了windows ...有一个类构造函数和析构函数(本机,不管理)。似乎我们没有像调用构造函数那样频繁地调用析构函数,所以随着时间的推移,我们泄漏了这些类的一些实例,并且每一个,我们也“泄漏”了一个隐藏的窗口,这个窗口随着时间的推移积累并导致桌面堆耗尽问题。从这里开始,我们设法追踪该类的实例未被销毁的地方,并且能够解决问题。

不满意我的很多,但我很好奇为什么Process Explorer对我来说没有像我预期的那样有用。所有这一次,它显示零用户对象,即使我知道该进程正在创建窗口对象。然后我意识到PE只能为在同一会话中运行的进程显示此数据。所以,我必须在会话零中运行它才能跟踪服务的windowo对象。在PsExec以及下面的帖子的帮助下,我能够在会话0中运行PE并切换到它。

https://superuser.com/questions/426868/interactive-session-0-in-windows-7

https://blogs.technet.microsoft.com/home_is_where_i_lay_my_head/2012/10/09/windows-8-interactive-services-detection-error-1-incorrect-function/

从那里,我确实可以看到该过程有超过1,000个用户对象。我也能够运行WinSpy并确认我的发现。当然,在这个阶段,它都是学术性的,但也许这对未来的某些人有用。