Java SE JVM Guide(JDK10)

参考:https://docs.oracle.com/javase/10/vm/

目录(持续更新...)

1、JVM技术概览

2、编译控制

2.1、写指令

· 编译器控制选项

· 写指令文件

· 写编译指令

· 写编译器指令的方法模板

· 编写内联指令选项

· 防止重复使用选项

2.2、理解指令

· 默认指令

· 修改指令

· 编译器控制和向后兼容性

2.3、使用指令文件命令

· 编译器指令和命令行

· 编译器指令和诊断命令

· 指令堆栈中的指令顺序

3、垃圾回收



1、JVM技术概览

自适应编译器、快速的内存分配和垃圾收集、线程同步


2、编译控制

2.1、写指令

· 编译器控制选项

Table 2-1 Common Options

Option Description Value Type Default Value

Enable

如果将指令设置为false,则隐藏指令并使其无法匹配。 此选项对于防止选项重复很有用。

bool

true

Exclude

从编译中排除方法。

bool

false

BreakAtExecute

设置断点以在调试JVM时在指定方法的开头停止执行。

bool

false

BreakAtCompile

设置断点以在调试JVM时在指定方法的开头停止编译。

bool

false

Log

仅在日志中放置指定的方法。 必须首先设置命令行选项  -XX:+LogCompilation.。默认值false将所有已编译的方法放在日志中。

bool

false

PrintAssembly

使用外部 disassembler.so 库打印字节编码和本机方法的汇编代码。 

bool

false

PrintInlining

打印哪些方法是内联的,以及在哪里。

bool

false

PrintNMethods

打印生成的nmethods。

bool

false

BackgroundCompilation

将方法编译为后台任务。 方法以解释器模式运行,直到后台编译完成。 false值将方法编译为前台任务。

bool

true

ReplayInline

Enables the same CIReplay functionality as the corresponding global option, but on a per-method basis.

bool

false

DumpReplay

Enables the same CIReplay functionality as the corresponding global option, but on a per-method basis.

bool

false

DumpInline

Enables the same CIReplay functionality as the corresponding global option, but on a per-method basis.

bool

false

CompilerDirectivesIgnoreCompileCommands

忽略所有CompileCommands。

bool

false

DisableIntrinsic

根据方法匹配条件禁用内在函数。

ccstr

No default value.

inline

强制或阻止基于方法匹配标准的方法内联。

ccstr[]

No default value.

Table 2-2 C2 Exclusive Options

Option Description Value Type Default Value

BlockLayoutByFrequency

从热路径移动不频繁的执行分支。

bool

true

PrintOptoAssembly

使用外部 disassembler.so 库在编译后打印生成的汇编代码。 这需要JVM的调试版本。

bool

false

PrintIntrinsics

打印使用哪种内在方法,以及在哪里。

bool

false

TraceOptoPipelining

跟踪流水线信息,类似于相应的全局选项,但基于每个方法。 这适用于缓慢和快速的调试版本。

bool

false

TraceOptoOutput

跟踪流水线信息,类似于相应的全局选项,但基于每个方法。 这适用于缓慢和快速的调试版本。

bool

false

TraceSpilling

跟踪变量溢出。

bool

false

Vectorize

跨矢量寄存器并行执行计算。

bool

false

VectorizeDebug

跨矢量寄存器并行执行计算。 这需要JVM的调试版本。

intx

0

CloneMapDebug

可以检查从矢量化生成的CloneMap。 这需要JVM的调试版本。

bool

false

IGVPrintLevel

指定在Oracle的Hotspot Ideal Graphic Visualizer(IGV)中打印编译器图形的点。 值越高意味着粒度越高。

intx

0

MaxNodeLimit

设置单个方法编译期间要使用的最大节点数。

intx

80000

· 写指令文件

  1. 创建一个. json文件扩展。指令文件编写使用JSON的语法的子集,包含轻微的增加和偏差。
  2. 组成模块:

    [  //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,
            },
        },
    ]

· 写编译指令

  1. 模板
        {
            match: [],
            c1: {
                //c1 directive options
            },
            c2: {
                //c2 directive options
            },
            //Directive options applicable to all compilers
        },
  2. 参数
     match: ["java*.*", "oracle*.*"],
  3. 配置c1编译器属性
            c1: {
                Enable: true,
                Exclude: true,
                BreakAtExecute: true,
            },
  4. 配置c2编译器属性
            c2: {
                Enable: false,
                MaxNodeLimit: 1000,
            },
  5. 配置编译器通用属性

            BreakAtCompile: true,
            DumpReplay: true,
  6. 清理文件
  • 检查重复执行选项。
  • 避免在公共选项中写c1-exclusive或c2-exclusive选项。
  • 如果c1或c2没有属性对应的指令选项,省略该编译器的属性语法。

示例:

    {
        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 方法模板

  1. 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()
  1. 通配符*
    • java/lang/String.indexOf*
    • *lang/String.indexOf*
    • *va/lang*.*dex*
    • java/lang/String.*
    • *.*
  2. 签名不能包含通配符
  3. 可选:写一个方法模式伴随内联指令选项,必须用前缀附加字符的方法模式。

· 编写内联指令选项

  • 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
        },
    },
]

2.2、理解指令

· 默认指令

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 使用

优先级:

  1. Compiler Control

  2. CompileCommand

  3. Command-line flags

  4. 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


2.3、使用指令文件命令

· 编译器指令和命令行

可以使用命令行界面在启动程序时添加和打印编译器指令。

只能在命令行中指定一个指令文件。 该文件中的所有指令都将添加到指令堆栈中,并在程序启动时立即生效。 通过在命令行添加指令,可以在程序的早期阶段测试指令的性能影响。 还可以专注于调试和开发程序。

通过命令行添加指令

以下命令行选项指定指令文件:

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)编号。

  1. 打开终端
  2. 输入 jcmd 命令

 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 不指定指令情况下启动程序

Java SE JVM Guide(JDK10)_第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 指定指令情况下启动程序

Java SE JVM Guide(JDK10)_第2张图片

将指令添加到正再运行的应用程序:

可以通过诊断命令将指令添加到正再运行的应用程序。

  • 将指令文件 File_B 中的指令添加到指令堆栈

    jcmd 11084 Compiler.directives_add File_B.json
  •  File_B 中的指令将会添加到指令堆栈的顶部

  • Figure 2-3 显示指定堆栈顺序从上到下为  [3, 1, 2, 0].

  • Figure 2-3 将指令添加到正再运行的应用程序

Java SE JVM Guide(JDK10)_第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 将多个指令添加到正再运行的应用程序

 

Java SE JVM Guide(JDK10)_第4张图片

从指令堆栈删除指令:

可以通过诊断命令从指令堆栈中删除最顶层的指令。

jcmd 11084 Compiler.directives_remove
  • 删除多个指令时,重复删除操作即可。不能删除默认指令。

  • Figure 2-5 显示指定堆栈顺序从上到下为 [5, 3, 1, 2, 0].

Java SE JVM Guide(JDK10)_第5张图片
 

清空指令堆栈中的指令

  • 清空指令堆栈中的指令

    jcmd 11084 Compiler.directives_clear
  • 除了默认指令外的所有指令将被清空

  • Figure 2-6 显示指定堆栈只剩 Directive 0 。

  • Figure 2-6 清空指令堆栈中的指令

Java SE JVM Guide(JDK10)_第6张图片

3、垃圾回收

详见:https://blog.csdn.net/www_changer/article/details/82584678

你可能感兴趣的:(java)