java 执行机制_Java类的执行机制

在完成将class文件信息加载到JVM并产生Class对象后,就可执行Class对象的静态方法或实例化对象进行调用了。在源码编译阶段将源码编译为JVM字节码,JVM字节码是一种中间代码的方式,要由JVM在运行期对其进行解释并执行,这种方式成为字节码解释执行方式

字节码解释执行

由于采用的为中间码的方式,JVM有一套自己的指令,对于面向对象的语言而言,最重要的是执行方法的指令,JVM采用了invokestatic、invokevirtual、invokeinterface、invokespecial四个指令来执行不同的方法调用。invokestatic对应的是调用static方法,invokevirtual对应的是调用对象实例的方法,invokeinterface对应的是调用接口的方法,invokespecial对应的是调用private方法和编译源码后生成的方法,此方法为对象实例化时的初始化方法(构造方法)。

Sun

JDK基于栈的体系结构来执行字节码,基于栈方式的好处是代码紧凑,体积小。线程在创建后,都会产生程序计数器(PC)和栈(Stack):PC存放了下一条要执行的指令在方法内的偏移量,栈中存放了栈帧,每个方法每次调用都会产生栈帧。栈帧主要分为局部变量区和操作数栈两部分,局部变量区用于存放方法中的局部变量和参数,操作数栈中用于存放方法执行过程中产生的中间结果,栈帧中还会有一些杂用空间,例如指向方法已解析的常量池的引用、其他一些VM内部实现需要的数据等。

a4c26d1e5885305701be709a3d33442f.png

1、指令解释执行

对于方法的指令解释执行,执行方式为经典冯诺依曼体系中的FDX循环方法,即获取下一条指令,解码并分派,然后执行。在实现FDX循环式有switch-threading、token-threading、direct-threading、subroutine-threading、inline-threading等多种方式。Sun

JDK的重点为编译成机器码,并没有在解释器上做太复杂的处理,因此采用了token-threading方式。为了让解释执行能更加高效,Sun

JDK还做了一些其他的优化,主要有:栈顶缓存和部分栈帧共享。

2、栈顶缓存

在方法的执行过程中,可看到有很多操作要将值放入操作数栈,这导致了寄存器和内存要不断的交换数据,Sun

JDK采用了一个栈顶缓存,即将本来位于操作数栈的值直接缓存在寄存器上,这对于大部分只需要一个值的操作而言,无需将数据放入操作数栈,可直接在寄存器计算,然后放回操作数栈。

3、部分栈帧共享

当一个方法调用另一个方法时,通常传入另一个方法的参数为已存放在操作数栈的数据,Sun

JDK在此做了一个优化,就是当调用方法时,后一方法可将前一方法的操作数栈作为当前方法的局部变量,从而节省数据copy带来的消耗。

编译执行

编译执行的效率较低,为提升代码的执行性能,SunJDK提供将字节码编译为机器码的支持,编译在运行时进行,通常称为JIT编译器。SunJDK在执行过程中对执行频率高的代码进行编译,对执行不频繁的代码则继续采用解释执行的方式,因此SunJDK又称为Hotspot

VM,在编译上SunJDK提供了两种模式client compiler(-client)和server

compiler(-server)。

client

compliler又称为C1,较为轻量级,只做少量性能开销比高的优化,它占用内存较少,适合桌面交互式应用,在寄存器分配策略上,JDK6以后采用的为线性扫描寄存器分配算法,在其他方面的优化主要有:方法内嵌、去虚拟化、冗余消除等。

1、方法内联

对于java面向对象的语言,通常要调用多个方法来完成功能,执行时,要经历多次参数传递,返回值传递及跳转等,于是C1采用了方法内联的方式,即把调用到的方法的指令直接植入到当前的方法中。(可在debug版本的JDK的启动参数加速-XX:PrintInlining来查看方法内联的信息)

2、去虚拟化

去虚拟化是指在装载class文件后,进行类层次的分析,如发现类中的方法只提供一个实现类,那么对于调用此方法的代码,也可进行方法内联,从而提升执行的性能。

3、冗余消除

冗余消除是指在编译时,根据运行时状况进行代码折叠或消除。如某个判断条件为false则可将条件内的代码消除。

Server

Compiler又称为C2,较为重量级,C2采用了大量传统编译优化技巧,占用内存会相对多,适用于服务器应用。和C1不同的主要是寄存器分配策略和优化的范围,寄存器分配策略上C2采用的为传统的图着色寄存器分配算法:由于C2会收集程序的运行信息(收集的信息主要有,分支的跳转/不跳转的频率,某条指令出新过的类型、是否出现过控制、是否出现过一场),因此其优化的范围更多在于全局的优化,而不仅仅是一个方法块的优化。

逃逸分析是C2进行很多优化的基础,逃逸分析是指根据运行状况来判断方法中的变量是否会被外部读取,如不会则认为此变量是逃逸的,基于逃逸分析C2在编译时会做标量替换、栈上分配和同步消除等优化。

1、标量替换

变量替换的意思简单来说就是用标量替换聚合量。这种方式能带来的好处是,如果创建的对象并未用到其中的全部变量,则可以节省一定的内存。

2、栈上分配

如果变量没有逃逸,那么C2会选择在栈上直接创建对象实例,而不是在JVM堆上,在栈上分配的好处一方面是更加快速,另一方面是回收时随着方法的结束,对象也被回收了。

3、同步消除

同步消除是指如果发现同步的对象未逃逸,那也没有同步的必要了,在C2编译时会直接去掉同步。

除了C1\C2外,还有一种较为特殊的编译:OSR(On

Stack

Replace)。OSR和C1、C2的最主要的不同点在于OSR编译只替换循环代码体的入口,而C1、C2替换的是方法调用的入口,因此在OSR编译后会出现的现象是方法的整段代码都被编译了,但在只有循环代码体部分才执行编译后的机器码,其他部分仍然是是解释执行方法。

默认情况下,SunJDK根据机器配置来选择C1或C2模式,当机器配置CPU超过2核且内存超过2GB及默认为C2模式,但在32位机器上时钟选择的都是C1模式,也可在启动时通过增加-client或-server来强制指定。

SunJDK为提升程序执行性能,在C1好C2上做了很多努力,其他各种实现的JVM也在编译执行上做了很多的优化,SunJDK之所以未选择在启动时即编译成机器码,主要是因为:静态编译并不能根据程序的运行状况来优化执行的代码,C2这种方式是根据运行状况来进行动态编译的,如分支判断、逃逸分析等,这些措施会提升程序执行的性能,在静态编译的情况下是无法实现的,给C2收集运行数据越长时间,编译出的代码也会越优;解释执行比编译执行更节省内存;启动时解释执行的启动速度比编译在启动更快。

当程序在未编译期间解释执行会比较慢,因此需要取一个权衡值,在SunJDK中主要依据方法上的两个计数器是否超过阈值,其中一个计数器为调用计数器,即方法被调用的次数;另一个为回边计数器,即方法中循环执行部分代码的执行次数。下面介绍两个计数器对应的阈值

(1)ComplieThresold

该值是指方法被调用多少次后,就编译为机器码,在client模式下默认为1500次,在server模式下为10000次,可通过在启动时天机-XX:CompilerThreshold=10000来设置该值

(2)OnStackReplacePercentage

该值用于计算是否触发OSR编译的阈值,默认模式下client为933,server模式下为140,该值可通过在启动时添加-XX:OnStackReplacePercetage=140来设置。

反射执行

反射执行是Java的亮点之一,基于反射可动态调用某对象实例中对应的方法、访问查看对象的属性等,无需再编写代码时就确定要创建的对象。这使得Java可以很灵活的实现对象的调用,例如MVC框架中通常要调用实现类中的execute方法,但框架在编写时是无法知道实现类的,在Java中则可以通过反射机制直接去调用应用类的实现类中的execute方法。

这种方式对于框架之类的代码而言非常重要,反射和直接创建对象实例调用方法的最大不同在于创建的过程、方法调用的过程是动态的。这也是的采用反射生成执行方法调用的代码并不像直接调用实例对象代码,编译后就可直接生成对象方法调用的字节码,而是只能生成调用JVM反射实现的字节码了。

要实现动态的调用,最直接的方法就是动态生成字节码,并加载到JVM中执行,SunJDK采用的即为这种方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571205.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ES6中object对象属性

//es5中定义对象属性要么字面量、要么点、要么[],变量与空格在这些方法中没有得到好的支持 /在es6中可以这么定义: let wwww; let obj1{w};//obj1{w:www},属性与值相同,简写 let obj2{[w]:b};//obj2{www:b},支持[]变量定义属性 let obj3{[ws]:c};//obj3{…

java csv 导出_java实现CSV文件输出

java实现CSV文件输出 收藏在很多时候我们都需要将一些数据集合以某种文件格式输出,其中CSV文件输出是一种比较常用的方式.下面是一个简单的实现CSV文件输出的代码,与大家共享.public static boolean createCsv(HttpServletResponse Response, QueryData qryData, String[][] co…

java resultset转json_ResultSet到JSON的最有效转换?

以下代码ResultSet使用JSONArray和将转换为JSON字符串JSONObject。import org.json.JSONArray;import org.json.JSONObject;import org.json.JSONException;import java.sql.SQLException;import java.sql.ResultSet;import java.sql.ResultSetMetaData;public class ResultSet…

论如何入门地使用vscode

微软大法好啊 这货更像是个gedit 以下内容只适合Oiers使用 本文档只适合新手引导的阶段使用 下载 这个是链接 可见这东西是和Emacs一样跨系统的 不知道为什么下载速度贼快 配置 还记得我们用Emacs的时候配置那叫一个可怕 虽然使用vscode也要配置 不过我们在配置它的时候就比Ema…

Java 面向对象的设计原则

一、 1、面向对象思想的核心: 封装、继承、多态。 2、面向对象编程的追求: 高内聚低耦合的解决方案; 代码的模块化设计; 3、什么是设计模式: 针对反复出现的问题的经典解决方案,是对特定条件下(…

java获取panel面板画笔_java - paintComponent()与paint()和JPanel vs Canvas在画笔类型的GUI中 - 堆栈内存溢出...

我一直试图找到一个解决方法,但没有找到一个,特别是对于getGraphics()方法:如何将图形添加到面板?你记得需要绘制的变量是什么,并在paintComponent()中使用它。 例如,您在其他问题中尝试做的事情如下&#…

springboot jpa 创建数据库以及rabbitMQ分模块扫描问题

在使用jpa过程中,如果没有在配置中加入自动创建实体对于的sql,则需要提前创建建表语句 spring.jpa.properties.hibernate.show_sqltrue spring.jpa.properties.hibernate.format_sqltrue spring.jpa.hibernate.ddl-autoupdate 建表语句需要注意的点:需要…

cpp_06_缺省构造_拷贝构造_拷贝赋值_初始化表

1 构造函数 1.1 构造函数可重载&#xff1a; 构造函数可以通过形参表的差别化形成重载关系 重载关系的构造函数&#xff0c;通过构造函数的实参类型进行匹配 使用缺省参数可以减少构造函数重载的数量 // consover.cpp 构造函数的重载 #include <iostream> using name…

mysql sumif条件求和_sumif与sumifs条件求和函数详解,小白到大神的必经之路

在日常工作中我们经常需要根据某些条件进行求和&#xff0c;今天就给大家介绍下&#xff0c;Excel中的条件求和函数sumif和sumifsSumif函数第一个参数&#xff1a;Range&#xff1a;条件区域&#xff0c;用于条件判断的单元格区域。第二个参数&#xff1a;Criteria&#xff1a;…

第二类斯特林数总结

第二类斯特林数总结 标签&#xff1a; 第二类斯特林数 最近做题的时候遇到了一些跟第二类斯特林数有关的东西&#xff0c;发现网上的资料不是很多&#xff0c;于是写一篇博客来总结一下。 第二类斯特林数 定义 第二类斯特林数\(S(n,m)\)表示的是把n个不同的小球放在m个相同的盒…

python 装饰器 继承_Python设计模式之装饰器模式

装饰器模式无论何时我们想对一个对象添加额外的功能&#xff0c;都有下面这些不同的可选方法。如果合理&#xff0c;可以直接将功能添加到对象所属的类(例如&#xff0c;添加一个新的方法)使用组合使用继承注意&#xff0c;本文中的Decorator可以为装饰器或者修饰器。与继承相比…

Thread.join(), CountDownLatch、CyclicBarrier和 Semaphore区别,联系及应用

在java 1.5中&#xff0c;提供了一些非常有用的辅助类来帮助我们进行并发编程&#xff0c;比如CountDownLatch&#xff0c;CyclicBarrier和Semaphore&#xff0c;今天我们就来学习一下这三个辅助类的用法&#xff0c; 由于Thread.join()也和这三个类有类似用法&#xff0c;我也…

string转short java_[Java基础]之 数据类型转换

数据类型转换存在的意义数据类型转换&#xff0c;在实际的应用开发中&#xff0c;常常会对不同类型的数字类型进行计算&#xff0c;所以就用到了数据转换。一方面&#xff0c;使用算术计算符对数字进行运算时&#xff0c;系统在适当的时候回进行自动转换&#xff1b;另一放方面…

adb 静默安装_怎么实现Android APP静默安装

在 Android 中&#xff0c;如果要使用系统限制的权限(比如 android.permission.WRITE_SECURE_SETTINGS)&#xff0c;我们需要把程序安装到 /system/app/ 下。下面以 SecureSetting.apk 为例&#xff0c;演示这个操作。需要准备一台已经获得 Root 权限的手机。1、通过 USB 连接手…

跟我一起读postgresql源码(十六)——Executor(查询执行模块之——control节点(下))

5.ModifyTable节点 先看一个ModifyTable节点的例子&#xff1a; postgres# explain update test_01 set id 5 where name xxx;QUERY PLAN ---------------------------------------------------------------Update on test_01 (cost0.00..23.75 rows6 width48)-> Seq Sc…

java获取对象的子_java – 如何根据子对象字段获取父对象

家长班&#xff1a;public class Person {String firstName;String lastName;Long id;List phoneNumber new ArrayList<>();int age;public Person(String firstName, String lastName, int age, Long id, List phone) {super();this.firstName firstName;this.lastNam…

vscode格式化关于符合eslint检测语法配置

.js文件插件&#xff1a;JavaScript Standard Style配置&#xff1a;解决ES6语法格式化 {"files.associations": {"*.js": "javascriptreact"} }.vue文件 配置&#xff1a; {"vetur.format.defaultFormatter.js": "vscode-typesc…

二、配置数据源、SessionFactory、domain对象

1.在applicationContext.xml中配置数据源 <?xml version"1.0" encoding"utf-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:context"h…

IDEA建立Spring MVC Hello World 详细入门教程

引子&#xff0c;其实从.NET转Java已经有几个月时间了&#xff0c;项目也做了不少&#xff0c;但是很多配置都是根据公司模板或者网上教程比忽略画瓢&#xff0c;对其中最简单的配置和设置并不完全理解&#xff0c;依旧是小白用户。最近项目不忙&#xff0c;重新梳理了一下Spri…

java offsetdatetime_Java OffsetDateTime withHour()用法及代码示例

Java中OffsetDateTime类的withHour()方法返回此OffsetDateTime的副本&#xff0c;其中一天中的小时数按照参数中的指定进行了更改。用法:public OffsetDateTime withHour(int hour)参数&#xff1a;此方法接受单个参数hour&#xff0c;该参数指定要在结果中设置的一天中的小时&…