代码之家  ›  专栏  ›  技术社区  ›  David Hay

为什么getmessagew会在我的WPF应用程序中占用大量的CPU?

  •  10
  • David Hay  · 技术社区  · 14 年前

    我手上有一个很严重的抓痕。我正在研究应用程序中的WPF组件的性能问题。

    我们的.NET应用程序非常大,几乎完全是Windows窗体。作为新计划的一部分,我们用丰富的WPF UI重写了一个核心组件。有很多winforms<-->wpf interop正在进行这项工作,以将其粘合在一起,我怀疑这可能与我所看到的有所关联。

    当我在AntsProfiler中分析缓慢的操作时,我看到函数unsafenativeMethods.IntGetMessageW中发生了很多活动。Ants报告去那里的CPU活动和它对我们所有的业务逻辑和WPF呈现组合所做的一样多。该函数没有使用循环的托管代码下行链路,因此无论IntGetMessageW在做什么,都是我所追求的。

    我对Win32编程不太熟悉,但我知道在这种情况下消息循环的基本知识。我在这里看到的都不是我们手工做的任何事情——在我们的代码中,任何时候都不是我们直接与底层的messageloop本身或者可以在WPF调度器上访问的任何更复杂的东西交互。

    这里讨论的wpf组件是从窗口继承而来的(即,它不仅仅是控件/用户控件),我们使用showdialog从更高级别的逻辑中显示出来,该逻辑用于调用该组件的旧winforms版本上的showdialog。我们在wpf组件内部使用了一些windowsformsintegrationhost控件,以保持与wpf中无法重写的现有部分的兼容性。

    我已经研究了好几天了,但还没有找到很多东西。我一直在寻找与输入信息(鼠标和键盘)有关的模糊的帖子,但我不知道我能做些什么来验证这一点;我已经尝试过扼杀代码来删除我能做的每一个鼠标/键盘操作。

    我很难到达任何地方,主要是因为这一行代码是完全隔离的(不是我能指出的来自我们代码的任何东西的父或子代码),并且对它正在做的事情完全不透明。

    下面是ShowDialog函数的Ants调用图的图像,其中显示了要到达此处的调用路径: alt text

    我完全意识到这可能是作为WPF的一部分必须做的事情(尽管我们用WPF编写的其他组件不显示这种行为),或者这只是Ants探查器中一个非常奇怪的bug,但此时我需要以某种方式验证它。如果有人能告诉我这里到底发生了什么或者可能发生了什么——或者向我指出某种方式,我会自己去弄清楚,我会以你的方式指引各种好的业力。

    更新: 为了响应下面的一些讨论,这里是来自Ants的另一个视图——这一个更好地说明了我的困惑(这是在“CPU时间”模式下的Ants视图)。我匆忙地审查了部分代码,但没有系统相关功能:

    alt text

    谢谢你的关注!

    4 回复  |  直到 14 年前
        1
  •  0
  •   Jeff B    14 年前

    我在搜索同一问题的信息时发现了这个。我将添加我所知道的内容,看看是否有帮助:

    我在一个WinXP盒子上运行—WPF框架在Vista和Win7中比在XP中集成得多。其中一些原因可能是WPF是如何“在XP桌面上”运行的,而不是在它内部运行的。

    我运行的是纯本地WPF应用程序-没有WinForms或其他代码。

    我遇到了这个问题,试图确定为什么简单地滚动一个窗口会消耗100%的CPU并在执行时结巴。

    运行AQTimePerformanceProfiler,我看到IntGetMessageW占据了CPU使用率100%中最大的一部分。这不是因为IntGetMessageW正在等待消息,而是函数实际正在执行的操作。

    我还没有研究的一件事是,也许IntGetMessageW从来就不是一个快速的方法,也许WPF只是滥用了它。WPF中的数据绑定可能使用本机Win32消息泵更新WPF中的依赖属性。如果是这样,可能是我的窗口绑定太多了。

        2
  •  3
  •   Hans Passant    14 年前

    是的,这是正常的。任何GUI应用程序都是 总是 正在执行getmessagew(),等待Windows向其发送消息。它实际上并不是在燃烧CPU周期,而是在内部同步对象上阻塞,直到发出某种UI事件的信号。

    这当然会使分析UI应用程序变得困难,您确实需要单元测试来测试应用程序的子组件。

        3
  •  1
  •   LBushkin    14 年前

    分析应用程序时,需要区分 花费的时间 以一种方法和 CPU周期 消耗。 许多分析工具向您展示了在一个方法中花费的全部时间——在某些情况下,比如 GetMessageW 会很高的。GUI应用程序的主线程的所有活动都将在该方法中发生。不过,这不一定是个问题…这可能只是等待同步对象的主消息泵,而不是实际消耗周期。

    我建议您从使用AntsProfiler中的采样特性开始,识别调用的方法 最常 并将它们与消耗最多CPU周期的方法关联起来。 一旦您完成了这项工作,您就可以决定在哪里对应用程序进行检测,以便进一步深入了解调用图对于CPU最密集的地方是什么样子的。

    首先应该怀疑自己的代码。 很少有像WPF或Win32基础结构这样的东西导致性能低下或CPU利用率高。很可能,问题就在您的实现中的某个地方——它帮助您全面了解程序中CPU周期的使用位置。

    我建议你也花些时间 learning the capabilities of the profiler 最有效。 在您了解他们试图向您展示的是什么之前,分析人员可能是复杂和混乱的工具。如果你还没有开始的话,Redgate的链接导师应该是一个很好的开始。例如,时间线视图实际上可能是一个很好的地方,可以开始查看高CPU活动的发生位置,并将您的分析限制在那些执行代码段中。

    alt text

    调用图是蚂蚁中的另一个有用工具,因为它可以帮助您钻取代码中最昂贵的区域。关键是要确保您正在查看 总成本 不仅仅是 全部时间 .

    alt text

        4
  •  0
  •   Nicolas Repiquet    14 年前

    看来你的信息泵正在大量输出。看到您的消息队列中充满了什么类型的消息可能很有趣。你能在你的窗口上用spy++看看发生了什么吗?

    编辑

    我误解了这个问题。

    HansPassant是对的,您的程序只是在等待GetMessage来处理一些事件。

    推荐文章