参考:https://docs.oracle.com/javase/10/vm/
目录(持续更新...)
1、JVM技术概览
2、编译控制
2.1、写指令
· 编译器控制选项
· 写指令文件
· 写编译指令
· 写编译器指令的方法模板
· 编写内联指令选项
· 防止重复使用选项
2.2、理解指令
· 默认指令
· 修改指令
· 编译器控制和向后兼容性
2.3、使用指令文件命令
· 编译器指令和命令行
· 编译器指令和诊断命令
· 指令堆栈中的指令顺序
3、垃圾回收
自适应编译器、快速的内存分配和垃圾收集、线程同步
Table 2-1 Common Options
Option | Description | Value Type | Default Value |
---|---|---|---|
|
如果将指令设置为false,则隐藏指令并使其无法匹配。 此选项对于防止选项重复很有用。 |
|
|
|
从编译中排除方法。 |
|
|
|
设置断点以在调试JVM时在指定方法的开头停止执行。 |
|
|
|
设置断点以在调试JVM时在指定方法的开头停止编译。 |
|
|
|
仅在日志中放置指定的方法。 必须首先设置命令行选项 |
|
|
|
使用外部 |
|
|
|
打印哪些方法是内联的,以及在哪里。 |
|
|
|
打印生成的nmethods。 |
|
|
|
将方法编译为后台任务。 方法以解释器模式运行,直到后台编译完成。 false值将方法编译为前台任务。 |
|
|
|
Enables the same |
|
|
|
Enables the same |
|
|
|
Enables the same |
|
|
|
忽略所有CompileCommands。 |
|
|
|
根据方法匹配条件禁用内在函数。 |
|
No default value. |
|
强制或阻止基于方法匹配标准的方法内联。 |
|
No default value. |
Table 2-2 C2 Exclusive Options
Option | Description | Value Type | Default Value |
---|---|---|---|
|
从热路径移动不频繁的执行分支。 |
|
|
|
使用外部 |
|
|
|
打印使用哪种内在方法,以及在哪里。 |
|
|
|
跟踪流水线信息,类似于相应的全局选项,但基于每个方法。 这适用于缓慢和快速的调试版本。 |
|
|
|
跟踪流水线信息,类似于相应的全局选项,但基于每个方法。 这适用于缓慢和快速的调试版本。 |
|
|
|
跟踪变量溢出。 |
|
|
|
跨矢量寄存器并行执行计算。 |
|
|
|
跨矢量寄存器并行执行计算。 这需要JVM的调试版本。 |
|
|
|
可以检查从矢量化生成的CloneMap。 这需要JVM的调试版本。 |
|
|
|
指定在Oracle的Hotspot Ideal Graphic Visualizer(IGV)中打印编译器图形的点。 值越高意味着粒度越高。 |
|
|
|
设置单个方法编译期间要使用的最大节点数。 |
|
|
组成模块:
[ //Array of Directives
{ //Directive Block
//Directive 1
},
{ //Directive Block
//Directive 2
},
]
示例:
[ //Array of directives
{ //Directive Block
//Directive 1
match: ["java*.*", "oracle*.*"],
c1: {
Enable: true,
Exclude: true,
BreakAtExecute: true,
},
c2: {
Enable: false,
MaxNodeLimit: 1000,
},
BreakAtCompile: true,
DumpReplay: true,
},
{ //Directive Block
//Directive 2
match: ["*Concurrent.*"],
c2: {
Exclude:true,
},
},
]
{
match: [],
c1: {
//c1 directive options
},
c2: {
//c2 directive options
},
//Directive options applicable to all compilers
},
match: ["java*.*", "oracle*.*"],
c1: {
Enable: true,
Exclude: true,
BreakAtExecute: true,
},
c2: {
Enable: false,
MaxNodeLimit: 1000,
},
配置编译器通用属性
BreakAtCompile: true,
DumpReplay: true,
示例:
{
match: ["java*.*", "oracle*.*"],
c1: {
Enable: true,
Exclude: true,
BreakAtExecute: true,
},
c2: {
Enable: false,
MaxNodeLimit: 1000,
},
BreakAtCompile: true,
DumpReplay: true,
},
简化:
{
"match": "*Concurrent.*",
c2: {
"Exclude": true,
}
},
ccstr
方法模板
package/class.method(parameter_list)
. java/lang/String.indexOf()
其他格式
java/lang/String.indexOf()
java/lang/String,indexOf()
java/lang/String indexOf()
java.lang.String::indexOf()
*
java/lang/String.indexOf*
*lang/String.indexOf*
*va/lang*.*dex*
java/lang/String.*
*.*
inline: ["+java/lang*.*", "-sun*.*"]
inline: "+java/lang*.*"
使用 Enable
选项隐藏指令
改进前:
[
{
match: ["java*.*"],
c1: {
BreakAtExecute: true,
BreakAtCompile: true,
DumpReplay: true,
DumpInline: true,
},
c2: {
MaxNodeLimit: 1000,
},
},
{
match: ["oracle*.*"],
c1: {
BreakAtExecute: true,
BreakAtCompile: true,
DumpReplay: true,
DumpInline: true,
},
c2: {
MaxNodeLimit: 2000,
},
},
]
改进后
[
{
match: ["java*.*"],
c1: {
Enable: false,
},
c2: {
MaxNodeLimit: 1000,
},
},
{
match: ["oracle*.*"],
c1: {
Enable: false,
},
c2: {
MaxNodeLimit: 2000,
},
},
{
match: ["java*.*", "oracle*.*"],
c1: {
BreakAtExecute: true,
BreakAtCompile: true,
DumpReplay: true,
DumpInline: true,
},
c2: {
//Unreachable code
},
},
]
Directive: (default)
matching: *.*
c1 directives:
inline: -
Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000
c2 directives:
inline: -
Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000
[
{
match: ["*Concurrent.*"],
c2: {
MaxNodeLimit: 1000,
},
Exclude:true,
},
]
Directive:
matching: *Concurrent.*
c1 directives:
inline: -
Enable:true Exclude:true BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000
c2 directives:
inline: -
Enable:true Exclude:true BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:1000
Directive: (default)
matching: *.*
c1 directives:
inline: -
Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000
c2 directives:
inline: -
Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000
指令应用于代码基于方法匹配的过程。每个方法提交编译与指令堆栈的指令对应。
匹配方法:Compiler Broker匹配指令堆栈中的指令。
方法匹配过程:
当一个方法提交编译时,将方法的完全限定名称与指令堆栈匹配。找到的第一个匹配应指令用于此方法,剩余的指令堆栈被忽略。如果未找到匹配,则使用默认的指令。
活跃指令与应用指令的区别在于:
一个指令在指令堆栈中出现则为活跃指令
一个指令应用于代码则为应用指令
示例:
public int exampleMethod(int x){
return x;
}
以下指令2为应用指令
Directive 2:
matching: *.*example*
Directive 1:
matching: *.*exampleMethod*
Directive 0: (default)
matching: *.*
没有找到匹配指令的例子:
public int otherMethod(int y){
return y;
}
以下指令0位应用指令
Directive 2:
matching: *.*example*
Directive 1:
matching: *.*exampleMethod*
Directive 0: (default)
matching: *.*
编写新指令:
没有提供反馈机制来验证该指令应用于给定的方法。相反,一个分析器例如JMX用来测量应用指令的累积效应。
CompilerBroker忽略会造成不好结果的指令选项,如平台不提供支持的硬件指令。会显示一条警告消息。
指令选择有相同的限制作为典型的命令行标记
CompileCommand 和 command-line flags 可以独立于Compiler Control directives 使用
优先级:
Compiler Control
CompileCommand
Command-line flags
Default values
混合Compiler Control 和 CompileCommand示例:
Compiler Control:
Exclude: true
BreakAtExecute: false
CompileCommand:
BreakAtExecute: true
BreakAtCompile: true
Default values:
Exclude: false
BreakAtExecute: false
BreakAtCompile: false
Log: false
结果:
Exclude: true
BreakAtExecute: false
BreakAtCompile: true
Log: false
可以使用命令行界面在启动程序时添加和打印编译器指令。
只能在命令行中指定一个指令文件。 该文件中的所有指令都将添加到指令堆栈中,并在程序启动时立即生效。 通过在命令行添加指令,可以在程序的早期阶段测试指令的性能影响。 还可以专注于调试和开发程序。
通过命令行添加指令
以下命令行选项指定指令文件:
XX:CompilerDirectivesFile=file
启动Java程序时包括此命令行选项。 以下示例显示了此选项,启动TestProgram
:
java -XX:+UnlockDiagnosticVMOptions -XX:CompilerDirectivesFile=File_A.json TestProgram
在示例中:
-XX:+UnlockDiagnosticVMOptions
启用诊断选项,在命令行添加指令之前,必须输入此命令。
-XX:CompilerDirectivesFile
指定要添加到指令堆栈的一个指令文件
File_A.json
是一个指令文件,该文件可以包含多个指令,所有指令在程序启动时都会添加到活动的指令堆栈中。
如果 File_A.json
包含语法错误或格式错误的指令,则会显示错误消息, TestProgram
不会启动。
通过命令行打印指令:
在程序启动时或通过诊断命令添加其他指令时自动打印指令堆栈:
-XX:+CompilerDirectivesPrint
在命令行中包含此诊断命令:
java -XX:+UnlockDiagnosticVMOptions -XX:+CompilerDirectivesPrint -XX:CompilerDirectivesFile=File_A.json TestProgram
可以使用诊断命令来管理在运行时处于活动状态的指令。 可以在不重新启动正在运行的程序的情况下添加或删除指令。
制作单个完美指令文件可能需要一些迭代和实验。 诊断命令提供了强大的机制,用于在指令堆栈中测试指令的不同配置。 诊断命令允许添加或删除指令,而无需重新启动正在运行的程序的JVM。
获取Java进程标识号(Process Identification Number)
要测试指令,您必须找到正在运行的程序的处理器标识符(PID)编号。
jcmd
命令返回正在运行的Java进程的列表及其PID编号。如 TestProgram
:
11084 TestProgram
通过诊断命令添加指令
可以通过以下诊断命令将文件中的所有指令添加到指令堆栈中。
jcmd pid Compiler.directives_add file
示例:
jcmd 11084 Compiler.directives_add File_B.json
终端报告添加的各个指令的数量。 如果指令文件包含语法错误或格式错误的指令,则会显示错误消息,并且不会将文件中的指令添加到堆栈中,也不会对正在运行的程序进行任何更改。
通过诊断命令删除指令
从指令堆栈中删除最顶层的单个指令:
jcmd pid Compiler.directives_remove
要清除添加到指令堆栈的每个指令:
jcmd pid Compiler.directives_clear
无法指定要删除的整个指令文件,也无法通过任何其他方式批量删除指令。
通过诊断命令打印指令
可以使用诊断命令来打印正在运行的程序的指令堆栈。
打印完整指令堆栈的详细说明:
jcmd pid Compiler.directives_print
指令文件和指令中指令的顺序非常重要。 堆栈中最顶层,最佳匹配的指令具有高优先级,并应用于代码编译。
以下示例说明了示例指令堆栈中指令文件的顺序:
File_A
contains Directive 1
and Directive 2
.
File_B
contains Directive 3
.
File_C
contains Directive 4
and Directive 5
.
使用或不使用指令启动应用程序
启动 TestProgram
不包含指令文件:
TestProgram
java TestProgram
默认指令始终是指令堆栈最底层的指令。Figure 2-1 显示了将 Directive 0
作为默认指令。 如果未指定指令文件,则默认指令也是最顶层的指令,将获得优先级。
Figure 2-1 不指定指令情况下启动程序
启动 TestProgram
包含指令文件:
启动 TestProgram
包含 File_A.json
指令文件
java -XX:+UnlockDiagnosticVMOptions -XX:CompilerDirectivesFile=File_A.json TestProgram
TestProgram
启动,指令文件 File_A
被添加到指令堆栈, 指令文件最顶层的指令成为指令堆栈中最顶层的指令。
Figure 2-2 显示指定堆栈顺序从上到下为 [1, 2, 0].
Figure 2-2 指定指令情况下启动程序
将指令添加到正再运行的应用程序:
可以通过诊断命令将指令添加到正再运行的应用程序。
将指令文件 File_B
中的指令添加到指令堆栈
jcmd 11084 Compiler.directives_add File_B.json
File_B
中的指令将会添加到指令堆栈的顶部
Figure 2-3 显示指定堆栈顺序从上到下为 [3, 1, 2, 0].
Figure 2-3 将指令添加到正再运行的应用程序
将多个指令添加到正再运行的应用程序:
将指令文件 File_C
中的指令添加到指令堆栈
jcmd 11084 Compiler.directives_add File_C.json
Figure 2-4 显示指定堆栈顺序从上到下为[4, 5, 3, 1, 2, 0].
将 Directive 4
从指令堆栈中删除
Figure 2-4 将多个指令添加到正再运行的应用程序
从指令堆栈删除指令:
可以通过诊断命令从指令堆栈中删除最顶层的指令。
jcmd 11084 Compiler.directives_remove
删除多个指令时,重复删除操作即可。不能删除默认指令。
Figure 2-5 显示指定堆栈顺序从上到下为 [5, 3, 1, 2, 0].
清空指令堆栈中的指令
清空指令堆栈中的指令
jcmd 11084 Compiler.directives_clear
除了默认指令外的所有指令将被清空
Figure 2-6 显示指定堆栈只剩 Directive 0
。
Figure 2-6 清空指令堆栈中的指令
详见:https://blog.csdn.net/www_changer/article/details/82584678