jvm 早期优化与晚期优化

jvm除了对内存进行清楚还会再编译期(早期)以及运行期(晚期)进行一些优化处理,这篇文章就简单编写一下我理解到得编译期与运行期jvm帮我们做了那些优化处理。该文由于个人水平有限,理解不够深刻。所以有些可能重要的点,我并不理解就没有编写。如果要深入学习可以百度学习其他文章。

编译过程大致可以分为3个过程:
  1、解析与填充符号表过程。 (不清楚具体操作与优化,后期学习补充)
  
  2、插入式注解处理器的注解处理过程。
   JDK1.5之后,Java提供了对注解的支持,这些注解与普通的Java代码一样,在运行期间发挥作用。
   有了编译器注解处理的标准API后,我们的代码才有可能干涉编译器的行为,由于语法树中的任意元素,甚至包括代码注释都可以在插件之中访问到,所以使用插入式注解处理器在功能上有很大的发挥空间。
  
  3、分析与字节码生成过程。
   标注检查 、数据及控制流分析 、字节码生成 (不清楚具体操作与优化,后期学习补充)
   解语法糖 :语法糖是指在计算机语言中添加某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。 Java是一种“低糖语言”,常用的语法糖主要是之前提到的泛型、变长参数、自动装箱/拆箱等。虚拟机运行时不支持这些语法,它们在编译期还原回简单的基础语法结构,这个过程称为解语法糖。解语法糖的过程是由desuger()方法触发的。

草草结束上面内容,下面开始我主要想写的,以后有机会深入学习jvm得时候我会对上面进行补充,不足望谅解。


  • Java语法糖

    • 泛型和类型擦除
      泛型是JDK1.5新增的特性,它的本质是参数化类型的应用,也就是说所操作的数据类型被指定为一个参数,这种参数类型可以用于类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。

      在编译后的字节码文件中,就已经替换成原来的原生类型,也称为裸类型,并且在相应的地方插入了强制转型代码。

      擦除法所谓的擦除,仅仅是对方的Code属性中的字节码进行擦除,实际上元数据中还是保留了泛型信息,这也是我们能通过反射手段取得参数化类型的根本依据。

    • 自动装箱、拆箱与遍历循环

      自动装箱、拆箱在编译之后就被转换成了相应的包装和还原方法,如Integer.valueOf()与Integer,intValue()方法,而遍历循环则把代码还原成了迭代器的实现,这也是为何遍历循环需要被遍历类实现Iterable接口的原因。

      包装类的“==”运算在不遇到算术运算的情况下不会自动拆箱,以及它们equals()方法不处理数据转型的关系。

    • 条件编译
      Java语言使用条件为常量的if语句,此代码中的if语句不同于其他Java代码,它在编译阶段就会被运行,生成的字节码之中只包含条件正确的部分。

      Java语言中条件编译的实现,也是Java语言的一颗语法糖,根据布尔常量值的真假,编译器将会把分支中不成立的代码块消除掉,这是在解语法糖阶段实现的。

      Java语言中还有不少的其他语言糖,如内部类、枚举类、断言语句、对枚举和字符串的switch支持、try语句中定义和关闭资源等等。

  • 运行期优化:
    解析器与编译器:
    解析器:可以快速发挥作用,省去编译时间,立即执行,节约内存。
    编译器:把更多的热点代码编译为本地代码之后,可以获得更高的执行效率,提升效率。HotSpot虚拟机内置两个编译器Client Compiler(C1)与Server Compiler(C2)
    HotSpot虚拟机默认采用解释器与其中一个编译器直接配合的方式工作。虚拟机根据自身的版本以及宿主机器的硬件性能自动选择,也可以通过参数-client或者-server去强制指定虚拟机运行在Client模式还是Server模式。

    即时编译本地代码需要占用程序时间,要编译优化程度更高的代码,解释器要替编译器收集性能监控信息,这对解释器执行速度也有影响。为了在程序响应速度与运行效率之间达到平衡,HotSpot采用分层编译的策略。
    第0层,程序解释执行,不开启性能监控功能(Profiling),可触发第1层编译。
    第1层,也称C1编译,将字节码编译为本地代码,进行简单,可靠的优化,可以加入性能监控的逻辑。
    第2层,也称C2编译,也是将字节码编译为本地代码,但是会启动一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。
    因此使用C1获取更高效得编译速度,C2获取更好得编译质量。并且在解析执行时,无需承担收集性能监控信息得任务。

    编译对象与触发条件:
    会被即时编译器编译得热点代码有两类:

    • 被多词调用的方法
    • 被多次执行得循环体;方法执行中编译,因此形象地称之为栈上替换(On Stack Replacement,OSR,即方法栈帧还在栈上,方法就被替换了)

    热点探测判别方式:

  • 基于采样的热点探测

    周期性的检查各个线程的栈顶,如果发现某个方法经常出现在栈顶,则是热点方法。该方式实现起来简单,有效,还可以获取调用关系,但是无法精准确定热度,容易受线程阻塞和别的外界因素影响。

  • 基于计数器的热点探测

    为每个方法建立一个计数器,统计方法的执行次数,执行超过一定的阀值,则是热度方法。

  • Client Server 编译过程
    是一个相对简单快速得三段式编译器,主要关注点在于局部性得优化,而放弃耗时较长得全局优化手段。
    1.将字节码构造成一种高级中间代码HIR,期间如方法内联,常量传播等基本优化都是再生成HIR前完成。
    2.HIR转化为LIR,在转换之前进行如空值检测消除,范围检查消除等,从而使HIR更高效。
    3.在LIR上分配寄存器,并在LIR上做窥孔优化,产生机器码。成为本地代码。

  • 编译优化
    虚拟机中的具有代表性的优化技术:
    语言无关的经典优化技术之一:公共子表达式消除。
    语言相关的经典优化技术之一:数组范围检查消除。
    最重要的优化技术之一:方法内联
    最前沿的优化技术之一:逃逸分析

分析对象的动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递给其他方法,称为方法逃逸。甚至还有可能被外部线程访问到,比如赋值给类变量或可以在其他线程中访问到的实例变量,称为线程逃逸。

如果能证明一个对象不会逃逸到方法或线程之外,也就是别的方法或线程无法通过任何途径访问到这个对象,就可以为这个变量进行一些高效的优化:如:栈上分配、同步消除、标量替换等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值