Nashorn脚本的调试、跟踪与性能分析
1. 调试独立脚本
1.1 运行和调试准备
要在NetBeans中运行或调试独立的Nashorn脚本,首先需要在NetBeans IDE中打开脚本文件。打开脚本后,有两种方式运行脚本:
- 右键点击显示脚本的编辑器,选择“Run File”菜单项。
- 在脚本面板处于活动状态时,按“Shift + F6”。
1.2 设置断点
可以使用以下三种方法之一添加断点:
- 将光标放在要设置/取消断点的行,右键点击并选择“Toggle Line Breakpoint”菜单项来设置或取消断点。
- 将光标放在要设置/取消断点的行,按“Ctrl + F8”。首次按下此组合键设置断点,若断点已设置,再次按下则取消断点。
- 在脚本中添加
debugger
语句。当调试会话处于活动状态时,
debugger
语句的作用就像一个断点;否则,它没有任何效果。
1.3 开始调试
设置好断点后,有两种方式开始调试脚本:
- 右键点击脚本面板,选择“Debug File”菜单项。
- 在脚本面板处于活动状态时,按“Ctrl + Shift + F5”。
调试会话开始后,调试器会在第一个断点处停止。此时,底部会打开“Variables”面板,显示作用域内所有变量及其值。若要查看调试会话的其他详细信息,可使用主菜单“Window ➤ Debugging”下的菜单项。若关闭了某些调试面板,可使用“Window ➤ Debugging”菜单重新打开。
1.4 调试操作
当调试会话处于活动状态时,可以使用以下调试操作,这些操作可从主菜单“Debug”以及调试器工具栏获取:
| 调试操作 | 快捷键 | 描述 |
| — | — | — |
| Finish Debugger | Shift + F5 | 结束调试会话。 |
| Pause | 无 | 停止当前会话中的所有线程。 |
| Continue | Ctrl + F5 | 恢复程序执行,直到下一个断点。 |
| Step Over | F8 | 执行当前行,并将程序计数器移动到文件中的下一行。如果执行的行是对函数的调用,函数中的代码也会被执行。 |
| Step Over Expression | Shift + F8 | 允许你逐步执行表达式中的每个方法调用,并查看每个方法调用的输入参数和结果输出值。如果没有更多的方法调用,其行为与“Step Over”操作相同。 |
| Step Into | F7 | 执行当前行。如果该行是对函数的调用,并且有被调用函数的源代码可用,程序计数器将移动到函数的声明处;否则,程序计数器将移动到脚本中的下一行。 |
| Step Out | Ctrl + F7 | 执行当前函数中剩余的代码,并将程序计数器移动到调用该函数的行之后。如果你已经进入了一个不需要再调试的函数,可以使用此操作。 |
1.5 示例代码
以下是一个简单的判断质数的脚本示例:
// Check if n is divisible by any odd integers between 3 and sqrt(n).
function isPrime(n) {
var sqrt = Math.sqrt(n);
for (var i = 3; i <= sqrt; i += 2) {
if (n % i === 0) {
return false;
}
}
return true; // If we get here, it is a prime number.
}
// Check few nubmers for being primes
var num = 8;
var isPrimeNum = isPrime(num);
print(num + " is a prime number: " + isPrimeNum);
debugger;
num = 37;
isPrimeNum = isPrime(num);
print(num + " is a prime number: " + isPrimeNum);
2. 从Java代码中调试脚本
2.1 调试步骤
从Java代码调用脚本进行调试的方式略有不同。仅在脚本文件中设置断点并启动调试器,或从Java代码进入脚本进行调试是行不通的。以下是具体的调试步骤:
1.
设置断点
:需要在调用脚本引擎
eval()
方法的代码行设置断点。例如,在以下Java程序中,需要在调用
engine.eval(scriptReader);
的行设置断点:
// PrimeTest.java
package com.jdojo.script;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class PrimeTest {
public static void main(String[] args) {
// Construct the script file path
String scriptFileName = "primetest.js";
Path scriptPath = Paths.get(scriptFileName);
// Make sure the script file exists. If not, print the full
// path of the script file and terminate the program.
if (!Files.exists(scriptPath)) {
System.out.println(scriptPath.toAbsolutePath() + " does not exist.");
return;
}
// Get the Nashorn script engine
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
try {
// Get a Reader for the script file
Reader scriptReader = Files.newBufferedReader(scriptPath);
// Execute the script in the file
engine.eval(scriptReader); // First time, add a breakpoint here
}
catch (IOException | ScriptException e) {
e.printStackTrace();
}
}
}
-
启动调试
:在包含
PrimeTest类的编辑器面板处于活动状态时,按“Ctrl + Shift + F5”。调试器将在第35行的断点处停止。 -
进入脚本
:按“F7”进入
eval()方法调用,这将带你到AbstractScriptEngine.java文件。再次按“F7”,调试器将打开一个名为<eval>.js的文件,其中包含你试图通过Java代码使用Reader加载的primetest.js文件中的脚本。你可以滚动查看脚本并在<eval>.js文件中设置断点。 -
继续调试
:在
<eval>.js文件中设置好断点后,就可以进行正常的调试操作了。例如,使用“Continue”调试操作(F5)将在执行到下一个断点时停止。
2.2 注意事项
调试完成后,可以从Java代码(如本例中的
PrimeTest.java
文件)中移除断点。如果开始新的调试会话,调试器将在之前在
<eval>.js
文件中设置的断点处停止。需要注意的是,只需进入
<eval>.js
文件一次,后续的调试会话会记住之前会话设置的断点。
2.3 代码替换
在上述Java程序中,
try-catch
块中的代码可以替换为以下代码片段,程序的功能相同,但需要移除两个从
java.io
包导入类的导入语句:
try {
// Execute the script in the file
engine.eval("load('" + scriptFileName + "');"); // First time, add a breakpoint here
}
catch (ScriptException e) {
e.printStackTrace();
}
2.4 调试流程
graph TD;
A[设置eval()方法调用处的断点] --> B[启动调试器];
B --> C[调试器在断点处停止];
C --> D[按F7进入eval()方法];
D --> E[打开<eval>.js文件];
E --> F[在<eval>.js文件中设置断点];
F --> G[进行正常调试操作];
3. 脚本的跟踪与性能分析
3.1 启用选项
Nashorn支持调用点跟踪和性能分析。可以在
jjs
命令行工具以及嵌入式Nashorn引擎中启用这些选项。可以为引擎运行的所有脚本或每个脚本/函数启用跟踪和性能分析:
-
–tcs
选项:为所有脚本启用调用点跟踪,并将调用点跟踪信息打印到标准输出。
-
-pcs
选项:为所有脚本启用调用点性能分析,并将调用点性能分析数据打印到当前目录下名为
NashornProfile.txt
的文件中。
3.2 选择性跟踪和分析
可以在脚本或函数的开头使用以下四个Nashorn指令来选择性地跟踪和分析整个脚本或函数:
-
"nashorn callsite trace enterexit"
:相当于
-tcs=enterexit
。
-
"nashorn callsite trace miss"
:相当于
-tcs=miss
。
-
"nashorn callsite trace objects"
:相当于
-tcs=objects
。
-
"nashorn callsite profile"
:相当于
-pcs
。
需要注意的是,
–tcs
和
–pcs
选项是基于每个脚本引擎的,而这四个跟踪和分析指令是基于每个脚本和每个函数的。这些Nashorn指令仅在调试模式下启用,可以通过将
nashorn.debug
系统属性设置为
true
来启用Nashorn调试模式。这些指令在JDK8u40及更高版本中可用。
3.3 示例代码
以下是一个启用了Nashorn调用点性能分析选项的脚本示例,该脚本保存为
primeprofiler.js
文件:
// primeprofiler.js
function isPrime(n) {
// Profile this function only
"nashorn callsite profile";
// Integers <= 2, floating-point numbers, and even numbers are not primes
if (n <= 2 || Math.floor(n) !== n || n % 2 === 0) {
return false;
}
// Check if n is divisible by any odd integers between 3 and sqrt(n).
var sqrt = Math.sqrt(n);
for (var i = 3; i <= sqrt; i += 2) {
if (n % i === 0) {
return false;
}
}
return true; // If we get here, it is a prime number.
}
// Check few nubmers for being primes
var num = 8;
var isPrimeNum = isPrime(num);
print(num + " is a prime number: " + isPrimeNum);
num = 37;
isPrimeNum = isPrime(num);
print(num + " is a prime number: " + isPrimeNum);
3.4 运行脚本并生成分析文件
使用以下命令以启用Nashorn调试选项的方式运行
primeprofile.js
文件中的脚本:
c:\>jjs -J-Dnashorn.debug=true primeprofile.js
运行该命令后,将在当前目录下生成一个名为
NashornProfile.txt
的文件,其中包含
isPrime()
函数调用的性能分析数据。以下是
NashornProfile.txt
文件的内容示例:
0 dyn:getProp|getElem|getMethod:Math 438462 2
1 dyn:getMethod|getProp|getElem:floor 433936 2
2 dyn:call 650602 2
3 dyn:getProp|getElem|getMethod:Math 313834 1
4 dyn:getMethod|getProp|getElem:sqrt 283356 1
5 dyn:call 0 1
3.5 Java程序示例
以下是一个设置
nashorn.debug
系统属性并运行上述脚本的Java程序:
// ProfilerTest.java
package com.jdojo.script;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class ProfilerTest {
public static void main(String[] args) {
// Set the nashorn.debug system property, so the tracing and
// profiling directives will be recognized
System.setProperty("nashorn.debug", "true");
// Construct the script file path
String scriptFileName = "primeprofiler.js";
Path scriptPath = Paths.get(scriptFileName);
// Make sure the script file exists. If not, print the full
// path of the script file and terminate the program.
if (!Files.exists(scriptPath)) {
System.out.println(scriptPath.toAbsolutePath() + " does not exist.");
return;
}
// Get the Nashorn script engine
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
try {
// Get a Reader for the script file
Reader scriptReader = Files.newBufferedReader(scriptPath);
// Execute the script in the file
engine.eval(scriptReader);
}
catch (IOException | ScriptException e) {
e.printStackTrace();
}
}
}
运行该程序将在当前目录下创建一个
NashornProfile.txt
文件,文件内容与上述示例相同。
3.6 跟踪和分析流程
graph TD;
A[设置nashorn.debug系统属性为true] --> B[编写脚本并添加跟踪或分析指令];
B --> C[运行脚本(Java程序或jjs命令)];
C --> D[生成NashornProfile.txt文件];
D --> E[查看性能分析数据];
综上所述,NetBeans 8搭配JDK 8或更高版本支持在NetBeans IDE中调试Nashorn脚本,既可以运行和调试独立的Nashorn脚本,也可以在从Java代码调用Nashorn脚本时进行调试,调试器能够无缝地从Java代码跳转到Nashorn脚本。此外,Nashorn支持调用点跟踪和性能分析,可以通过命令行工具或嵌入式引擎启用这些选项,还可以使用特定的指令对脚本或函数进行选择性的跟踪和分析。
4. 调试和分析的实际应用场景
4.1 调试场景
在实际开发中,调试是发现和解决代码问题的重要手段。以下是一些常见的调试场景:
-
功能异常
:当脚本的功能没有按预期执行时,例如判断质数的脚本返回了错误的结果,可以通过设置断点,逐步执行代码,查看变量的值,找出问题所在。
-
性能问题
:如果脚本执行速度过慢,可以使用调试工具分析代码的执行流程,找出性能瓶颈,例如某个循环或函数调用消耗了过多的时间。
-
兼容性问题
:在不同的环境或版本中,脚本可能会出现兼容性问题。通过调试可以在不同的环境中运行脚本,观察变量和执行结果的差异,找出问题的根源。
4.2 跟踪和分析场景
跟踪和分析可以帮助开发者了解脚本的执行情况,优化代码性能。以下是一些常见的跟踪和分析场景:
-
性能优化
:通过分析调用点性能分析数据,可以找出哪些函数或方法调用频繁,消耗了较多的资源,从而对这些部分进行优化。
-
代码优化
:跟踪调用点信息可以帮助开发者了解代码的执行路径,发现不必要的函数调用或重复的代码,进行代码重构。
-
问题定位
:当脚本出现问题时,调用点跟踪信息可以提供更多的上下文,帮助开发者快速定位问题所在。
4.3 实际应用示例
假设我们有一个复杂的脚本,其中包含多个函数调用和循环。在开发过程中,发现脚本执行速度较慢,我们可以使用跟踪和分析功能来找出问题所在:
1. 在脚本开头添加
"nashorn callsite profile"
指令,启用调用点性能分析。
2. 运行脚本,生成
NashornProfile.txt
文件。
3. 分析
NashornProfile.txt
文件中的数据,找出调用次数较多或执行时间较长的函数。
4. 对这些函数进行优化,例如减少不必要的循环或函数调用。
5. 再次运行脚本,查看性能是否有所提升。
5. 总结与建议
5.1 总结
通过本文的介绍,我们了解了Nashorn脚本的调试、跟踪和性能分析的相关知识和操作方法:
-
调试
:可以在NetBeans IDE中调试独立的Nashorn脚本,也可以从Java代码中调试脚本。通过设置断点、使用调试操作(如Step Over、Step Into等),可以逐步执行代码,查看变量的值,找出问题所在。
-
跟踪和分析
:Nashorn支持调用点跟踪和性能分析,可以通过
–tcs
和
-pcs
选项为所有脚本启用,也可以使用Nashorn指令为特定的脚本或函数启用。跟踪和分析数据可以帮助我们了解脚本的执行情况,优化代码性能。
5.2 建议
在实际开发中,为了更好地利用调试、跟踪和分析功能,提高开发效率和代码质量,我们可以遵循以下建议:
-
养成调试习惯
:在开发过程中,遇到问题时及时使用调试工具进行排查,不要盲目猜测和修改代码。
-
合理使用跟踪和分析
:根据实际需求,选择合适的跟踪和分析选项,避免过度使用导致性能下降。
-
定期优化代码
:根据跟踪和分析结果,定期对代码进行优化,提高代码的性能和可维护性。
5.3 未来展望
随着技术的不断发展,Nashorn脚本的调试、跟踪和分析功能可能会不断完善和增强。例如,可能会提供更直观的调试界面、更详细的跟踪和分析数据,以及更智能的问题定位和优化建议。开发者可以关注这些发展趋势,不断提升自己的开发能力和效率。
5.4 操作总结表格
| 操作类型 | 具体操作 | 相关选项/指令 | 作用 |
|---|---|---|---|
| 调试 | 在NetBeans中打开脚本文件,设置断点,启动调试 | 无 | 找出代码中的问题 |
| 调试 |
从Java代码中调试脚本,设置
eval()
方法调用处的断点,进入脚本调试
| 无 | 调试从Java代码调用的脚本 |
| 跟踪和分析 |
在
jjs
命令行工具或嵌入式引擎中使用
–tcs
和
-pcs
选项
|
–tcs
、
-pcs
| 为所有脚本启用调用点跟踪和性能分析 |
| 跟踪和分析 | 在脚本或函数开头使用Nashorn指令 |
"nashorn callsite trace enterexit"
、
"nashorn callsite trace miss"
、
"nashorn callsite trace objects"
、
"nashorn callsite profile"
| 选择性地跟踪和分析脚本或函数 |
5.5 综合流程图
graph LR;
A[开发脚本] --> B{出现问题?};
B -- 是 --> C[使用调试工具排查];
C --> D[设置断点,逐步执行代码];
D --> E[查看变量值,找出问题];
B -- 否 --> F{需要优化性能?};
F -- 是 --> G[使用跟踪和分析功能];
G --> H[添加跟踪或分析指令];
H --> I[运行脚本,生成分析文件];
I --> J[分析数据,找出性能瓶颈];
J --> K[优化代码];
F -- 否 --> L[继续开发];
E --> M[修复问题,继续开发];
K --> N[再次运行脚本,验证性能提升];
N --> L;
通过以上的调试、跟踪和分析方法,开发者可以更高效地开发和优化Nashorn脚本,提高代码的质量和性能。希望本文的内容对开发者有所帮助,让大家在开发过程中能够更加得心应手。
超级会员免费看
1340

被折叠的 条评论
为什么被折叠?



