NetBeans IDE 4.1/5.0 Profiler 教程
本文章旨在介绍配合使用 NetBeans Profiler v5.0 或 Profiler Milestone 8 的内容。如果您使用的是 Milestone 5,请使用此版本。如果您使用的是 Milestone 6,请使用此版本。
预计持续时间:50 分钟
NetBeans Profiler 是一个功能强大的工具,它提供了有关应用程序运行时行为的重要信息。NetBeans Profiler 产生的开销相对来说较小,它可以跟踪线程状态、CPU 性能和内存使用情况。本教程将向您介绍如何使用 NetBeans Profiler 来完成以下操作:
- 监视应用程序的运行时行为,其中包括:
- 堆内存大小
- 垃圾回收统计信息
- 线程计数
- 线程状态:运行、休眠、等待、受阻
- 确定应用程序方法使用的 CPU 时间
- 监视应用程序创建对象的过程
先决条件
本教程假定您已经具有了一些基本的 Java 编程和 NetBeans IDE 使用经验。
教程所需的软件:
本文档使用的表示法
- <NETBEANS_HOME> - NetBeans IDE 安装目录
- <USER_HOME> - 用户的 home 目录
- <tutorial_root> - 解压缩教程 zip 文件所在的目录
- 本文档使用 <tutorial_root> 来表示解压缩此教程的 zip 文件所在的目录。此教程的 zip 文件的名称为 profilertutorial.zip。
- 将教程 zip 文件解压缩到 <tutorial_root> 目录时,系统会创建一个名为 netbeansprofiler 的子目录。例如,在 Windows 操作系统中,如果已将教程 zip 文件解压缩到驱动器 E:\ 的根目录中,则系统会创建 E:\netbeansprofiler 子目录。在 Solaris/Linux 操作系统中,如果已将教程 zip 文件解压缩到 /home/username 目录中,则系统会创建 /home/username/netbeansprofiler 子目录。
教程练习
参考资源:
练习 0:安装并配置教程环境
在开始学习教程之前,请先检查以下内容:
- 启动 NetBeans IDE,并确认 IDE 已打开。通过选择 Profile > Help > About Profiler...,验证是否安装了 NetBeans Profiler
。
- 在 Windows 操作系统中,双击 NetBeans IDE 图标
- 在 Solaris/Linux 操作系统中,打开终端窗口,然后键入 <NETBEANS_HOME>/bin/netbeans
- 仅限 NetBeans IDE v4.1:安装所需的修补程序。
- 从 Tools 菜单选择 Update Center,以访问 NetBeans 更新中心。
- 确保选中了 NetBeans Hotfix Update Center,然后单击 Next 按钮。建立连接后,将显示一个更新列表。
- 在 NetBeans Hotfix Update Center 条目下,选择 "NetBeans Profiler (J2EE Projects - Tomcat5 Support)"。该操作还将自动选择 "Tomcat 5 Server" 条目。
- 单击 Next(下一步) 按钮,并按照说明进行操作以便 IDE 可以安装这些修补程序。
练习 1:监视 Swing 应用程序中的线程状态(15 分钟)
本练习的学习目的:
在本练习中,您将学习如何使用 NetBeans Profiler 监视 J2SE 应用程序中的线程状态。这样,您就可以诊断样例应用程序中的性能问题。
背景信息:
Swing 为 J2SE 应用程序提供了图形用户界面组件。Swing 库会使用到多个线程,利用 NetBeans Profiler 这一功能强大的工具,您可以分析出每个线程所花费的处理时间,从而利用这些分析信息来解决性能问题。
执行步骤:
- 选择 File > Open Project。找到 <tutorial_root>/netbeansprofiler/exercises 文件夹。选择 exercise1 文件夹,然后单击 Open Project Folder 按钮。
- 在 Projects() 窗口中,右键单击 exercise1 条目并选择 Clean and Build Project。然后,再次右键单击 exercise1 条目并选择 Run Project。此时,将显示该程序的窗口,如下所示。

- 将 Seconds Before Notification 设置为 30。
- 单击 Start! 按钮。请注意,该程序无法正确地刷新屏幕。
- 单击 Exit 按钮。请注意,该程序根本不会作出响应。
- 将另一个窗口放在该窗口的某一部分上,以遮挡该窗口的视图。当移开另一个窗口时,您会注意到样例应用程序没有相应地刷新其窗口。如下面的示例所示。

- 30 秒后,最终将显示一个消息框,如下所示。单击消息框上的 OK 按钮。

- 应用程序窗口将再次开始响应。单击 Exit 按钮将其关闭。
- 选择 Profile > Profile Main Project。
- 如果出现一个对话框,询问您是否允许修改项目生成脚本,请单击 OK。如下面的示例所示。

- 将会显示 Profile 对话框。单击占据较大区域的 Monitor Application 按钮。
- 应选中 Enable Threads Monitoring 复选框。
- 单击 Run 按钮。如果显示一个对话框,指示您必须先收集 Profiler 的校准信息,请单击 OK 按钮。如下面的示例所示。

选择 Profile > Advanced Commands > Run Profiler Calibration。完成校准后,Profiler 会显示一个对话框,请单击 OK 按钮。如下面的示例所示。

要进行性能分析,请返回至上面的第 9 步。
- 完成上述步骤后,将启动该应用程序,并且 IDE 会显示 Profiler 控制面板,如下所示。

- Profiler 将在其主窗口中显示线程状态,如下面的示例所示。

它使用颜色编码来显示线程状态。
- 绿色:线程正在运行或准备运行。
- 紫色:线程正在调用 Thread.sleep(),处于休眠状态。
- 黄色:线程正在调用 Object.wait(),处于等待状态。
- 红色:线程在尝试访问同步的块或方法时受阻。
- 找到样例 Swing 应用程序的窗口(NetBeans IDE 窗口可能在其上面)。单击样例应用程序中的 Start! 按钮,同时监视标记为 AWT-EventQueue-0 的线程所发生的变化。它将变为绿色并持续这种状态整整 30 秒钟,如以下样例所示。
此图形显示了应用程序没有响应的原因。标记为 AWT-EventQueue-0 的线程是 Swing 用来处理窗口事件的事件分发线程 (Event Dispatch Thread, EDT)。在正常运行的 Swing 应用程序中,EDT 的大部分时间处于等待状态而运行的时间却很少,因为它只有在分发事件时才会运行很短的一段时间。但是,如果应用程序中的事件处理程序未立即返回,则程序将停止响应,就像在此示例中一样。
- 30 秒后,屏幕将显示应用程序的消息框。找到该消息框(NetBeans IDE 窗口可能在其上面)并单击 OK 按钮。然后,单击样例应用程序的 Exit 按钮,将其关闭。
- Projects 窗口与 Profiler 控制面板共享同一个空间;单击 Projects 标签将会显示 Projects 窗口。
- 在 Projects 窗口中,双击 exercise1 条目以将其展开,然后展开 Source Packages 和 profilingthreads 条目。右键单击 DisplayForm.java 条目并选择 Open。
- 在包含 DisplayForm.java 的编辑器窗口中,取消第 132 行至第 157 行的代码块注释。提示:如果未将编辑器配置为显示行号,请选择 View > Show Line Numbers。
- 在包含 DisplayForm.java 的编辑器窗口中,取消(或注释掉)第 122 行到第 128 行的代码块注释。下图突出显示了取消注释的代码块。

- 选择 File > Save。您刚才删除了未正确使用 EDT 的代码,并利用了更稳定可靠的解决方案来替代它。现在,应用程序可以及时地作出响应。
- 选择 Build > Build Main Project(或按 F11 键)。
- 选择 Profile > Profile Main Project。
- 将会显示 Profile 对话框。单击占据较大区域的 Monitor Application 按钮。
- 确保选中了 Enable Threads Monitoring。
- 单击 Run 按钮。
- 当显示样例程序时,单击 Start! 按钮。请注意,此时的性能分析线程图已经发生了变化,如以下示例所示。
EDT 为黄色,应用程序创建的名为“Our SwingWorker #1”的线程为绿色。由于 EDT 不是用来执行耗时任务的,因此,按钮和其他程序控件仍保持响应的状态。
- 在样例程序中单击 Exit 按钮。
- 右键单击 Profiler 图形中的 AWT-EventQueue-0 线程,然后选择 Thread Details。Profiler 会显示一个饼图,表明了每种状态所花的时间;如以下示例所示。
该图形可以帮助您判断程序在每个线程中所花费的时间是否恰当。上述示例是代码修复后的示例,因此,它显示了 EDT 在大部分时间中都处于等待状态的情形,这正好是该线程应具有的行为。
- 在 Projects 窗口中,右键单击 exercise1 条目,然后选择 Close Project。
小结:
在本练习中,您学习了如何使用 Profiler 来启动应用程序,以及如何解释 Profiler 的线程信息图形,以此来跟踪 Swing 应用程序中的性能问题。
返回页首
练习 2:确定某个方法使用的 CPU 时间(15 分钟)
本练习的学习目的:
在本练习中,您将学习如何使用 Profiler 来确定某个应用程序的方法所花费的时间。
背景信息:
CPU 的性能问题通常与应用程序的特定功能有关。例如,在报告系统中,某个报告的运行速度可能比其他报告慢。只分析应用程序中出现性能问题的部分,可以大大减少 Profiler 产生的开销。在本练习中,您将使用 NetBeans Profiler 来检查 Web 应用程序中 CPU 的使用情况。在练习 3 中,我们仍然使用该样例 Web 应用程序来说明如何通过 Profiler 查找内存泄漏。
执行步骤:
- 选择 File > Open Project。找到 <tutorial_root>/netbeansprofiler/exercises 文件夹。选择 exercise2 文件夹,并确保选中 Open As Main Project。单击 Open Project Folder 按钮。
- 在 Projects 窗口中,单击 exercise2 条目,然后从菜单中选择 Build > Clean and Build Main Project。
- 从菜单中选择 Profile > Profile Main Project。如果出现一个对话框,询问您是否允许修改项目生成脚本,请单击 OK。
- 将会显示 Select Profiling Task 对话框。
- 单击 Analyze Performance 按钮。
- 选择 Part of Application 单选按钮。然后,单击位于 Part of Application 单选按钮旁边的 Select 按钮。此时将显示 Specify Root Methods 窗口。
注意:下面的三个步骤仅适用于 Milestone 8。
- 在 Specify Root Methods 窗口中,单击 Add 按钮以添加要分析的根方法。将会显示 Select Method 窗口。
- 在 Select Methods 窗口中,单击 Select 按钮。Profiler 将显示 Go To Class 窗口。
- 在 Class Name 文本字段中输入
Per。等待 IDE 为您显示适用的类列表。选择 Performance 类。单击 Open 按钮打开其方法列表。
注意:下面的两个步骤只适用于 Profiler v5.0。
- 在 Specify Root Methods(指定根方法) 窗口中,单击 Add From Project...按钮以添加要分析的根方法。将会显示 Select Methods 窗口。
- 在 Class Name 文本字段中,键入 demo.Performance,然后按 Enter 键。
- 在 Root Methods 列表中单击 processRequest 方法以将其选中,然后单击 OK 按钮。您刚才已将 demo.Performance.processRequest 选中为性能分析的根方法。这意味着,Profiler 将分析 demo.Performance.processRequest 方法和它调用的所有方法,以及这些方法又调用的所有方法,依此类推。Profiler 将从 demo.Performance.processRequest 开始,通过分析方法调用图形来确定哪些方法需要分析。它将只分析那些需要分析的方法,应用程序的其余部分将在没有任何性能分析开销的情况下继续以最快的速度运行。
- 在 Specify Root Methods 窗口中单击 OK 按钮。
- 在 Analyze Performance 窗口中,从过滤器列表中选择 Quick Filter,然后单击位于 Quick Filter 条目旁边的“...”按钮指定不进行分析的方法。将显示 Set Quick Filter 窗口。验证是否已选中了 Exclusive 单选按钮。然后,在 Filter Value 文本字段中输入 org.apache 并单击 OK 按钮。这样,Profiler 将不分析所有 org.apache 包(及其子包)中的方法,即使这些方法被选定的根方法调用也是如此。这会减少性能分析的开销,并过滤掉无关的信息。
- 在 Select Profiling 窗口中,单击 Run 按钮。如果出现一个对话框,要求您提供校准信息,请单击 OK 按钮;在 Profiler 显示的对话框说明校准已完成后,请单击该对话框的 OK 按钮。
- IDE 将启动 Tomcat,并在 Web 浏览器窗口中显示 Web 应用程序的 index.jsp 页。同时,将在后台运行 Profiler。注意:默认情况下,将在成为焦点的浏览器窗口中显示 index.jsp 页;您可能需要打开另一个浏览器窗口,以便在运行 Web 应用程序时可以阅读这些说明。
- 因为已选择了 demo.Performance.processRequest 作为根方法,所以,您需要使用导致该根方法运行的 Web 应用程序部分:在 Web 浏览器中,单击 Performance Problems 转至 Performance 演示页。在 Performance 演示页上的输入文本字段中输入 123456。请不要选中 optimized 选项。单击 Submit Query 按钮,计算小于或等于 123456 的最大素数。
- 需要几秒钟的时间才能出现响应,这是因为计算最大素数的算法存在一些性能问题。同时,在监视 processRequest 方法的性能时,Profiler 也会产生一些开销。
- 当浏览器中显示 123449 结果后,请单击
按钮,或者选择 Profile > Take Snapshot of Collected Results。单击位于 CPU 使用情况快照底部的 Combined 标签。Profiler 将显示最新的性能结果,如下所示。
顶部窗口显示了从根方法开始的完整方法调用图形。底部窗口是重点描述的部分;它显示了应用程序中的热点,即执行时间最长的那些方法。
- 要查看并解释这些结果,请注意 processRequest 方法总共运行的时间为 4308 毫秒 (ms)。然而您会发现,运行 processRequest 方法本身的指令只花费了很少的时间,processRequest 的 "self time" 仅为 10.1 毫秒。绝大部分时间花在了 processRequest 调用的其他方法上。底部窗口中显示的热点是按 "self time" 进行排序的。通过查看该列表,您可以看到 calculate 方法占用了 97.8% 的执行时间。考虑到为 calculate 方法分配的工作量,这就不足为奇了。
- 为了帮助您确定如何优化应用程序,NetBeans Profiler 可以识别代码中无法预料的瓶颈,也可以识别妨碍应用程序随意缩放的瓶颈。单击热点列表中的 calculate 条目以了解时间究竟花在哪些地方,这会更新调用图形窗口以显示 calculate。因为 calculate 方法不调用任何其他方法,所以请右键单击 calculate 条目,然后选择 Go To Source 以便检查源代码。您会发现它使用了效率很低的算法,所以应该重新设计这种算法。
- 选择 Profile > Reset Collected Results 以清除 Profiler 的缓冲区。要将 calculate 的运行时与优化的算法 calculate2 作比较,请在 Web 浏览器中选中 optimized 选项,然后单击 Submit Query。等待显示结果,然后重新选择 Profile > Take Snapshot of Collected Results。请注意,processRequest 方法只运行了 107 毫秒,而 calculate2 方法所花的时间还不到执行时间的 10%!

- 注意:我们将继续在本练习的基础上进行下面的练习,因此,请不要关闭任何窗口。
小结:
在本练习中,您学习了如何使用 Profiler 执行方法性能分析。
返回页首
分析对象创建过程以查找内存泄漏(20 分钟)
本练习的学习目的:
作为练习 2 的后续练习,我们将在本练习中学习如何解释某些监视应用程序创建对象过程的 Profiler 图形。下面将显示一个内存泄漏示例。
执行步骤:
- 本练习是在练习 2 的基础上进行的,因此,请务必遵循练习 2 中的步骤。
- 从菜单中选择 Profile > Profile Main Project。如果出现一个对话框,询问您是否要停止当前的 Profiler 进程以启动新进程(如下所示),请单击 Yes 按钮继续执行。
将会显示 Select Profiling Task 对话框。
- 在 Select Profiling Task 对话框中,单击占据较大区域的 Monitor Application 按钮。
- 单击 Run 按钮。IDE 将会左侧显示 Profiler 控制台。单击
按钮,或者选择 Profile > View > Telemetry Overview。NetBeans Profiler 将在底部的输出窗口中显示三个图形,如下所示。
在左侧的图形中,红色的阴影部分表示分配的 JVM 堆大小。紫色的覆盖部分表示实际使用的堆空间大小。在上面的示例中,上次更新所分配的堆大小已超过了 20 MB。其中,实际用来保存 Java 对象的堆大小略大于 10 MB。
右侧图形显示了 JVM 中的活动线程数。
中间的图形显示了两种重要的堆统计信息。
- 蓝线是 JVM 执行垃圾回收的时间占执行时间的百分比,它是以图形右侧上的 Y 轴为参照绘制的。JVM 执行垃圾回收所花的时间不能用来运行应用程序。因此,如果蓝线占据较大的百分比,则需要考虑调整 JVM,方法是:配置更大的堆大小(请参阅 -Xmx 参数文档),或者转换到不同的垃圾回收算法中。
-
红线表示存活的生成数,它是以图形左侧的 Y 轴为参照进行绘制的。存活生成数是指 JVM 堆上所有 Java 对象不同生存期的数量,其中“生存期”被定义为对象存活时的垃圾回收次数。如果存活生成数的值较小,则表明堆上的大部分对象的存活时间基本相同。但是,如果存活生成数的值随着时间的变化而增长到一个很高的比率,则表明应用程序正在分配新的对象,同时保持对已分配的多个旧对象的引用。如果实际上不再需要这些旧对象,则应用程序正在浪费(或“泄漏”)内存。
- Profiler 可以对 CPU 性能或内存使用情况进行详细的分析(也称为测试),但不能同时进行这两种分析。要了解有关在 JVM 堆上分配对象以及执行对象的垃圾回收的详细信息,请修改 Profiler 的设置。单击
按钮,或者选择 Profile > Modify Profiling。
- 单击 Analyze Memory Usage 按钮。
- 选择 Record both object creation and garbage collection 单选按钮。
- 选中 Record Stack Trace for Allocations 复选框。
- 单击 OK 按钮。
- 现在,您已经选择了分析内存使用情况,您需要运行应用程序以确定它是否有效地使用了内存。单击 Memory Leak 转至 MemoryLeak 演示页。
- 在 MemoryLeak 演示页上,单击 Start Leaking。
- 请注意存活生成数图形中的峰值,如以下示例所示。这表明可能出现了内存泄漏。
- 选择 Profile > View > Live Results。Profiler 将显示 JVM 堆中分配的对象的动态视图。默认情况下,它将按每个类的所有实例使用的字节数进行排序。由于怀疑可能出现了内存泄漏,因此,请单击 Generations 列,按每个类的不同对象生存期数量对显示结果进行排序。下面显示了得到的显示结果示例。
这些列提供了对象分配和内存使用情况信息。
- Allocated Objects 是 Profiler 正在监视的对象数。在本示例中,共监视了 38 个 float[] 实例。默认情况下,该数字约为应用程序实际分配的对象数的 10%。通过只监视已创建对象的一部分,Profiler 可以显著地减少它在 JVM 中的开销,这样,应用程序就几乎可以按最快的速度运行了。
- Live Objects 是仍在 JVM 堆中并因此占用内存的已分配对象数。
- 两个 Live Bytes 列显示了活动对象所占用的堆内存量。一个列显示图形,另一个列显示文本。
- Avg.Age 值是使用活动对象计算的。每个对象的生存期是它存活时的垃圾回收次数。生存期总和除以活动对象数得到的结果就是 Avg.Age。
- Generations 值是使用 Live Object 计算的。与 Avg.Age 相同,对象生存期是它存活时的垃圾回收次数。Generations 值是活动对象的不同生存期数量。
- 随着程序继续运行,Profiler 将更新显示结果。请留意 float[] 和 double[] 条目。请注意其生成数值是如何持续增加的。结果是,float[] 和 double[] 在列表中持续上移。最终,它们会显示在列表的顶部,紧靠 java.util.HashMap$Entry(其生代数值也在不断增加)下方。随着应用程序继续运行,java.util.HashMap$Entry、float[] 和 double[] Generations 值持续增加,但任何其他类没有增加。如下面的示例所示。
- 要了解导致 Generations 值持续增加的原因,请选择 Profile > Take Snapshot of Collected Results。按 Generations 对显示结果进行排序。右键单击 double[] 条目,然后选择 Show Allocation Stack Traces。Profiler 将显示所有分配了一个或多个 double[] 对象的方法。如下面的示例所示。
请注意,在分配了 double[] 对象的方法中,只有一个方法创建了具有较大 Generations 值的 double[] 对象。该方法是 run(),它位于具有相应名称 demo.memoryleak.LeakThread 的类中。
- 右键单击 run() 方法条目,然后选择 Go To Source...。Profiler 将显示源代码,如下所示。
请注意,正在分配 double[] 和 float[] 对象,并随后将其放在 HashMap 中。但一直并未删除它们,这意味着,HashMap 保留的引用将会妨碍 JVM 对这些对象进行垃圾回收。这是非常典型的 Java 内存泄漏:将对象放在 Map 中,然后就忘记处理它们了。由于本示例中使用的 Map 就是 HashMap,因此,关联的 java.util.HashMap$Entry 对象也出现了泄漏。
- 选择 Profile > Stop 来结束性能分析会话,或者单击
按钮。
- 在 Projects 窗口中,选择 exercise2 条目,然后从菜单中选择 File > Close Project。
小结:
在本练习中,您学习了如何使用 Profiler 来监视应用程序创建对象的过程。您还看到了 Profiler 在应用程序出现内存泄漏时所提供的各种类型的分析指数。
返回页首
恭喜您!您已成功地完成了 NetBeans IDE 4.x Profiler 教程。