Runtime Spy 是 Eclipse.org 提供的核心工具 (Core Tools)之一,它是特别设计的一个透视图及一组视图,用于帮助您找到并诊断插件启动性能问题。本文介绍了如何发现可能会导致启动时间过长的常见设计错 误,以及如何去纠正它们。其中的一个案例研究说明了Runtime Spy 如何用于提高 IBM WebSphere Studio Application Developer 的启动性能。上一篇文章,也就是 第1 部分,对 Runtime Spy 进行了介绍。
阅读完本系列文章的 第 1 部分 后,您应该已经对 Runtime Spy 如何来帮助您查找启动问题的位置有了大体的认识。让我们通过一些特定的例子来弄明白如何用它减少您的插件启动时间。为了让话题更有可读性,我们将探讨一些在 Runtime Spy 帮助下纠正的问题,这些问题的纠正是 IBM WebSphere Studio Application Developer 性能提高的一个方面。
注意:核心工具只能运行于 Eclipse 版本 2.x。在本文发表时,它们还不能运行于 Eclipse 3.0 驱动程序上;编号为 47518 的 bug 描述了这一问题。
为提高一个基于 Eclipse 的应用程序的启动性能,一般来说有两个目标:
这两个目标共同的原则是 尽可能延迟代码的执行。您可以采用的一些方法:
通过延迟插件的激活,会给用户一种产品更为灵活的印象。尽管 累积的CPU 时间是完全相同的,但是相对于在最开始强制完成,将其分解为若干小块在较长的一段时间内分步完成会进一步降低人们的注意力。在第一次调用时(也就是启动您 的产品或者打开第一个透视图、编辑器或视图时)尤其不应该有延迟,因为正是在这个时候用户最关注于工作的完成而没有太多耐心。
|
Runtime Spy 为您提供了用于跟踪三种加速启动方法的基本统计表,如图 1 所示。
您的第一个目标是让
Activated Plugins视图中出现的条目减到最少。对于那些出现在列表中的插件,您的第二个目标应该是让
Loaded Classes视图中出现的条目减到最少。Activated Plugins 视图中的
Startup time列将为您指出那些启动时间较长的插件。在 Activated Plugins 中选择
按钮可以更新
Stack Trace视图,让您明白
插件 为何被加载,在 Loaded Classes 视图中选择
按钮将为您说明
类为何被加载。
|
让我们以一个如何使用 Runtime Spy 来诊断和纠正启动代码错误的例子来开始。如您将看到的,这些修正不会在绝对意义上“提高”启动性能,而是延迟了启动开销,这样会让用户感觉产品整体上更快。底层的 Eclipse 产品在这一点上做得非常好,它会随着您的使用而将启动开销分解为小块分阶段进行。这是 Eclipse 的延迟插件加载策略的基础。
为对情况进行第一次观察,让我们启动 Studio 时只打开 Runtime Spy 透视图。这样应该会加载几乎最少的插件并以最快的速度启动,如图 2 所示。
|
注意插件名末尾的星号。这些插件是在负责启动 Eclipse 的插件被激活时加载的,那个插件名为 application plug-in。这个插件提供了一个实现 org.eclipse.core.runtime.applications 扩展点的 IPlatformRunnable 接口的类。默认地,Workbench UI 插件提供对这个接口的一个实现,来创建工作台窗口,收集对主菜单栏、工具栏等等的动作贡献 (action contributions),一般情况下还要为事务处理准备好 Eclipse 工作台用户界面。
实际上消耗的时钟时间将会比 Activated Plugins 视图中显示的 Startup time 列的和要多。这是因为后者不包括 Platform Runtime 加载之前 JVM 的运行时间或者插件启动之外的 CPU 运行时间。在图 2 所示的例子中,从启动配置启动 Run-time Workbench 时起实际上的启动时间大约是 13 秒。其中还包括启动配置本身为构建插件列表等任务而引入的程序调试时间 (development-time) 开销。
即使加上这些开销,启动时间还是非常少,不是吗?
让我们按下
按钮来更新活动的插件列表。就是那样!图
3 中是我们的第一个困惑。
被选中的那些插件是初始化时激活的。那么另外 11 个插件呢?或许有一些是因 Runtime Spy 透视图而加载的。更为有趣的是,图 3 中有一些看起来可疑的 Studio 插件。列表顶部显示的是“cheatsheet”和“internet”。它们是什么?为什么现在被加载?回到用户界面,我们在 Help下拉菜单下找到了与第一个插件相关的选项,如图 4 所示。
一般只有新用户才会去选择 Cheat Sheets菜单选项,所以我们为什么还要在启动时为加载它们的相关插件而付出代价呢? Workbench > Startup首选参数页提示了答案,如图 5 所示。
org.eclipse.ui.startup 扩展点可能是版本 2.0 一直有争议的 API 之一。当工作台窗口打开时它可以全权要求 Workbench UI 激活插件,而不受延迟加载策略限制。如果一个插件的清单定义了这一扩展点,那么它的插件类必须实现 IStartup.earlyStartup 方法。
有对这个 API 的合法使用。由于文章长度有限,不能尽述这个列表中每一个条目。所以让我们来考虑如上面图 5 所示添加的两个插件的合法性:
首先您可能会疑惑为何 Workbench 会定义一个 Startup 首选参数页。可以取消选择列出的插件之一,让用户有机会选择用减少的功能换取更快速的启动。例如,有经验的开发者不需要 Cheat Sheets 层叠菜单提供的提示,可以选择禁用它对 org.eclipse.ui.startup 扩展点的贡献,这样就删除了 Help > Cheat Sheets 菜单选项。如果您自己的插件对这个扩展点有贡献,那么要记住这一点。也就是说,要保守地编写您的插件代码,假定插件类的 IStartup.earlyStartup 方法可能还没有被调用。
回到我们在图 3 中的例子,考虑列表中没有星号的插件 com.ibm.etools.internet 。图 6 中它的栈记录确定了为什么这个插件在工作台窗口打开后被激活。
Workbench 的 run 方法被高亮了,对扩展点的贡献在这里被处理。自此以后激活的插件或者是对 startup 扩展点有贡献,或者是对其中的引用有贡献。
|
让我们打开 J2EE 透视图来查看一些 Studio 特定内容。(如果您想诊断一个简单些的情形,那么打开一个单一的视图,比如
Window
> Show View > DB Servers,而不要打开相应的透视图;那样已激活插件的列表会短很多。)打开 J2EE
透视图后,回到 Runtime Spy 并选择 Activated Plugin 的
按钮。
哇!列表中的插件数从 22 跳到了 73,增加了 20 秒的插件激活时间(先前总的时间也只有三秒多)。图 7 的显示中以插件的激活顺序对它们进行排序,最近激活的插件显示于顶部。
公平地讲,Runtime Spy 增加了开销,尤其是当需要捕获栈记录时,所以从半热态启动 (warm start) 时,实际上不加修正 (uninstrumented) 消耗的总的时间接近 37 秒。但是让我们来看一下是否有一些启动插件之外的插件有可能不必启动。为节省空间,下面这个列表并不完全,因为我们认为基本的组件比如 EMF、JDT 和 J2EE UI 是需要的。但是这些呢?
到 现在并没有与数据库相关的视图或者编辑器被打开。而为什么关系数据库模式中心 (6) 和那么多其他数据库相关的插件被激活了?插入的“可以被延迟”注释表示 Eclipse 有能力以体系化的解决方案使它们在需要之前不被激活,这只是关于属性的一种特殊情况。但是,即使全面地考虑,这些大部分都是无足轻重的。然而,还是有一些 插件消耗了大量的启动时间,而且,如我们所看到的,它们的开销与处理扩展点期间插件激活紧密联系在一起。下一节更全面地解释了这一开销,并对启动开销是如 何产生的进行了研究。然后我们将返回到我们对 J2EE 透视图启动的分析。
通过避免对 subuilder 插件(按它的插件清单的说法,它是 Stored Procedure和 UDF Builder)的激活来节省启动时间看起来可以成功,因为它需要用去总时间的 10%。此外,它几乎是在激活序列的最后(73 个中的第 72 个),所以,进行“修剪 (trim off)”可能要比避免次序靠前的插件激活更为简单。这个插件激活的栈记录见图 8。
Studio 的源代码不需要去理解发生了什么;栈记录就足以指出原因。Eclipse 类 PartPane 管理您看到的那些选项卡视图,包括 J2EE Hierarchy、 Package Explorer和 Navigator 视图。如图 8 所示,在选择的文本下方,选项卡视图 PartPane 正在尝试创建与 J2EE Hierarchy 选项卡相关联的视图的一个实例,类的名字为 J2EEView 。进一步查看记录的上方,我们看到这个类反过来调用了一个帮助者 (helper),然后这个帮助者调用了 createExecutableExtension 方法。
IConfigurationElement.createExecutableExtension 方法值得特别注意。当您调试您自己的性能问题时,您将会发现,这个方法导致了 Rumtime Spy 没有发现的很多插件的激活案例。为更好地理解它做了些什么以及它如何影响插件激活,考虑清单 1 中给出的简单的扩展点贡献。您可能会发现,这与 第 1 部分中规范的“Heloo Eclipse”样例的清单是相同的。
|
注意对
插件的类加载器 (classloader) 负责在它的库中解析对类的引用。类加载器将插件引用映射到它们相应的包含有插件类的 JAR 文件,比如我们的例子,
SampleAction 。因此,Workbench
UI 插件不必“知道”通过属性引用的类,比如
回到图 8 中所示的栈记录,我们可以发现,在所选择的文本中部的代码通过调用 createExecutableExtension 对扩展贡献进行处理 —— 看吧! 插件开始加载了。我们现在要寻觅的是明摆着的问题的答案:这时需要加载它吗?可以将它的加载向后延迟吗?
实际上所有会激活另一个插件的类最终都可以追溯到对 createExecutableExtension 方法的调用。这些调用的调用参数指明了属性名(通常是 “ class ”)和它的值,即要加载的类的全名。这就带我们回到了导致激活(此插件)的插件扩展贡献,在我们的例子中也就是 subuilder 插件。清单 2 是它的清单的摘录。
|
就参数而言,这个扩展贡献看起来类似于用来定义菜单选项贡献的 org.eclipse.ui.popupmenu 扩展点;更确切地说,它定义了一个标签(属性“name”),位置(属性“group”),目标(属性“view”),还有最特别的,处理程序(属性 “class”)。Eclipse 扩展与这个特殊实现的区别是,Eclipse 的扩展创建一个委派类作为菜单选项的代理。直到菜单选项真正被选择时,相应的处理程序类才会被创建,因而延迟了包含此处理器类的插件的激活。将同样的代理 策略应用到前面的例子中,J2EE 透视图的打开快了差不多 7 秒。创建 NewSQLSPAction 实例和激活包含它引用的类的插件的开销并没有消除,而是改变为随取随付 (pay-as-you-go)。
|
现在您应该知道为什么本文的子标题定为“成功的骗局”了。这完全是为了满足用户的期望,并让用户不去理会您希望他们不要去注意的东西。在这个特例中,现在启动更快了,但是稍后如果用户启用数据库工具,他们还要是付出同样多的 CPU 开销。那是可以接受的,因为开销是以化整为零的方式付出,而且,更重要的是,它使延迟更接近用户期望付出代价的相关动作。
记住,目标是 尽可能延迟代码的执行,不仅因为它可以带来感觉上性能的提高,还因为最容易用于优化速度的代码是永远不执行的代码。Eclipse 的插件体系结构让您可以容易地创建达成此目的的扩展,Runtime Spy 帮助您找到那些可以对实现进行改进的情形。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/374079/viewspace-130681/ ,如需转载,请注明出处,否则将追究法律责任。