您的位置:软件测试 > 开源软件测试 > 开源单元测试工具 >
客户机应用程序的性能测试
作者:网络转载 发布时间:[ 2013/2/21 14:52:40 ] 推荐标签:

SWT 和 JFace 提供了几个不同的类,帮助您在几个缓存中管理 GDI 资源。 缓存往往比您想的更灵巧。如何以及何时使用缓存并不总是显而易见的。 设计时应该注意的几个问题是:

    GDI 泄漏总是不可接受的,必须进行处理。
    处理完泄漏后,您应该考虑下面两个问题:
        应用程序需要的总共的 GDI 资源数目。
        创建这些资源导致的开销。

总共的 GDI 资源数目

您需要清醒地了解应用程序所需要的总共的 GDI 资源数目, 以及有多少资源是副本。 副本相当重要,因为您只要有可能应该共享 GDI 资源以便降低应用程序使用的资源数目。 很容易创建副本,而且您可以都没有意识到(我曾修改了 Sleak 工具使之发现副本, 并将此改变以及其他有用的改变添加到 Eclipse 中。)

创建 GDI 资源所需的开销

一般而言,创建字体和图像耗费的资源比创建颜色多。 根据应用程序的不同,图像的创建可能成为某些用户动作的重大开销。 如果遇到这种情况,您可以考虑使用一些 SWT/JFace 所提供的缓存。

如果可能,应让平台来管理资源。当您 在平台扩展中指定图像或图标属性时 —— 比如视图、动作等 —— 平台负责保证资源被正确地创建和删除。 好的代码往往是您无需编写并维护的代码。 上述提示的合理推论是可能时使用当前平台的字体和图像以提高共享。

只要有可能,应共享资源。为此,行之有效的方法是把资源集中到 一个公共包中。您可以将此视为重构公共资源。

每个 UI 包都有一个与之相关的 ImageRegistry。 该注册项可用于存储常用图像。这里的关键是常用。我曾见到过开发人员把所有的资源都 放到了这个注册项内,这并不合适。该注册项维护着一个由名称 > 图像或名称 > 图像描述符构成的映射。 图像描述符是对图像的轻量描述;它们并没有与之相关的任何 GDI。 您可以用图像描述符提前得到图像注册项,那么当 首次需要用到该图像时,注册项会为您创建它。

对于较为不常用的图像,您可以自行创建或删除之,此外您还可以使用 LocalResourceManager。其构造函数的一种形式采用了小部件。 以此方式创建时,LocalResourceManager 会在销毁小部件时清空 与之相关的资源。

侦听器泄漏(Listener leaking)

侦听器相关的泄漏是 UI 代码常常出现的问题(请参阅 参考资料)。 侦听器泄漏往往会浪费内存和时间。当您向一个对象添加侦听器时, 您是在小部件和侦听器之间创建了一个直接的、牢固的关联(参看图 2)。只要小部件存在, 侦听器及其引用的一切都会一直驻留在内存中。 当小部件或它的父容器被关闭, SWT 删除侦听器,从而打破那个牢固的关联。 我曾见过的很多代码都说明了开发人员往往在这个问题上不甚清楚。

只要从中添加侦听器的对象会及时删除,您无需删除 JFace/SWT 侦听器。 关键是理解从中添加侦听器的对象的生命周期。 不管什么时候要向某个对象中添加侦听器,您都需要自问一下, 侦听器被添加到哪个对象,侦听器的生命期有多长。

举例而言,假设应用程序创建了一个视图。该视图包含一个按钮。 在您构建该视图时,您为按钮添加了一个选择侦听器,以便应用程序能够对按钮单击作出响应。 您无需为删除按钮的侦听器而对视图添加一个删除侦听器, 您也无需为按钮被撤销时删除按钮的侦听器而对按钮再添加一个删除侦听器。 SWT 会在按钮被撤销时执行对按钮侦听器的删除。您不必写这些冗余的代码和管理多余的工作。

在 RCP 应用程序中,经常会有某人创建一个视图并将其自身添加为 workbench 页侦听器。 Workbench 页 往往很长寿,直到该应用程序关闭,workbench 页才会被关闭(从而清空侦听器)。 在此情况下,您不应该依赖 workbench 页清空侦听器关联。您应当在视图被关闭时把该视图作为侦听器删除。

我曾在一个聊天程序中看到过另一个受惑于对象生命周期的例子。 每当打开一个聊天窗口,都会向伙伴列表添加一个侦听器。 聊天窗口永远不删除侦听器,只要伙伴列表没有被撤销,不会有什么问题。 终结果是越来越多的侦听器被添加到伙伴列表,而且它们永远不会被删除。 需要强调的是这不仅是内存泄漏,也是对性能的破坏。 侦听器泄漏的后果是,每个聊天窗口以及它所有可访问的对象都驻留在内存。 同时,每次当伙伴列表向列表内的侦听器发信号,都会浪费时间去通知那些本来已经被关闭的聊天窗口。

还有一种常见的情形,是把侦听器添加到偏好存储以便您能够在偏好改变时更新 UI。 我曾见过有开发人员在创建视图或创建动作时添加偏好存储侦听器。 问题在于如果您不删除偏好存储侦听器,您会导致侦听器累积,因为 一般而言,偏好存储只有在应用程序关闭时才会被关闭。

动作是一个特殊的例子。动作并不真的有生命周期。 它们被创建后,即使被撤销或不再使用,您也并没有对它有什么控制能力。 这意味着当您创建一个动作时,您一般不应该向其他对象添加侦听器, 因为您并没有好的方法以删除那些侦听器。

如何发现侦听器泄漏
为发现侦听器泄漏,我推荐两个方法:

    审查代码:我会搜寻应用程序代码中向对象添加侦听器的位置,在那些位置上我认为 侦听器的生存时间超过我的预期。对这些侦听器列表后,我一般在运行时使用调试器 验证我的假设。即使每个 addListener 都对应有 removeListener 也并不代表没有问题, 因为开发人员往往会犯一个错误,是把 removeListener 包含到某个方法中, 他们以为该方法会被调用而实际上却没有。

    使用剖析器或差异分析,按如下步骤:
        启动应用程序。
        预热。
        得到一个内存快照。
        做 5 次动作(打开聊天窗口、读取邮件消息等)。
        得到一个内存快照。
        分析应用程序对象的实例数目。 如果有侦听器泄漏的话,比如说,您可能会发现有多出的 5 个本不应存在的侦听器。


结束语

我希望本文能为您提供一些关于如何在不同构建之间度量应用程序中堆使用的想法, 还有几个手工技术用于发现并处理不可避免的泄漏。 如果您还没有做好准备,试着跟踪应用程序在构建时耗费的资源量。 做了这些之后,您可以尝试进行堆分析。 即便您一开始对于堆转储还做不了什么,在构建时收集这些转储对于日后使用具有极大价值。 开始收集堆转储之后,您能够对域对象做差异分析。从小做起,当您熟悉这些技术后可以加入更多的分析。

上一页12345下一页
软件测试工具 | 联系我们 | 投诉建议 | 诚聘英才 | 申请使用列表 | 网站地图
沪ICP备07036474 2003-2017 版权所有 上海泽众软件科技有限公司 Shanghai ZeZhong Software Co.,Ltd