Java之深入JVM - 字节码执行引擎(转)

JVM - 字节码执行引擎 介绍JVM执行引擎相关知识;说明解释器、即时编译器工作流程; 阅读详情

本文为转载,https://www.cnblogs.com/royi123/p/3569511.html

 前面我们不止一次的提到,Java是一种跨平台的语言,为什么可以跨平台,因为我们编译的结果是中间代码—字节码,而不是机器码,那字节码在整个Java平台扮演着什么样的角色的呢?JDK1.2之前对应的结构图如下所示:

从JDK1.2开始,迫于Java运行始终笔C++慢的压力,JVM的结构也慢慢发生了一些变化,JVM在某些场景下可以操作一定的硬件平台,一些核心的Java库甚至也可以操作底层的硬件平台,从而大大提升了Java的执行效率,在前面JVM内存模型和垃圾回收中也给大家演示了如何操作物理内存,下图展示了JDK1.2之后的JVM结构模型。

那C++和Java在编译和运行时到底有啥不一样?为啥Java就能跨平台的呢?

 我们从上图可以看出。

C++发布的就是机器指令,而Java发布的是字节码,字节码在运行时通过JVM做一次转换生成机器指令,因此能够更好的跨平台运行。如图所示,展示了对应代码从编译到执行的一个效果图。

 我们知道JVM是基于栈执行的,每个线程会建立一个操作栈,每个栈又包含了若干个栈帧,每个栈帧包含了局部变量、操作数栈、动态连接、方法的返回地址信息等。其实在我们编译的时候,需要多大的局部变量表、操作数深度等已经确定并写入了Code属性,因此运行时内存消耗的大小在启动时已经已知。

在栈帧中,最小的单位为变量槽(Variable Slot),其中每个Slot占用32个字节。在32bit的JVM中32位的数据类型占用1个Slot,64bit数据占用2个Slot;在64bit中使用64bit字节填充来模拟32bit(又称补位),因此我们可以得出结论:64bit的JVM比32bit的更消耗内存,但是又出32bit机器的内存上限限制,有时候牺牲一部分还是值得的。Java的基本数据类型中,除了long、double两种数据类型为64bit以外,boolean、byte、char、int、float、reference等都是32bit的数据类型。

在栈帧中,局部变量表中的Slot是可以复用的,如在一个方法返回给上一个方法是就可以通过公用Slot的方法来节约内存控件,但这在一定程度省会影响垃圾回收,因此JVM不确定这块Slot空间是否还需要复用。

 Slot复用会给JVM的垃圾回收带来一定影响,如下代码:

复制代码

 1 package com.yhj.jvm.byteCode.slotFree;
 2 
 3 /**
 4 
 5  * @Described:Slot局部变量表 没有破坏GCRoot情况演示
 6 
 7  * @VM params :-XX:+PrintGCDetails -verbose:gc
 8 
 9  * @author YHJ create at 2012-2-22 下午04:37:29
10 
11  * @FileNmae com.yhj.jvm.byteCode.slotFree.SlotFreeTestCase.java
12 
13  */
14 
15 public class SlotFreeTestCase {
16 
17     /**
18 
19      * @param args
20 
21      * @Author YHJ create at 2012-2-22 下午04:37:25
22 
23      */
24 
25     @SuppressWarnings("unused")
26 
27     public static void main(String[] args) {
28 
29        //case 1
30 
31        byte[] testCase = new byte[10*1024*1024];
32 
33        System.gc();
34 
35 //     //case 2
36 
37 //     {
38 
39 //         byte[] testCase = new byte[10*1024*1024];
40 
41 //     }
42 
43 //     System.gc();
44 
45 //     //case 3
46 
47 //     {
48 
49 //         byte[] testCase = new byte[10*1024*1024];
50 
51 //     }
52 
53 //     int a = 0;
54 
55 //     System.gc();
56 
57 //     //case 5
58 
59 //     byte[] testCase = new byte[10*1024*1024];
60 
61 //     testCase=null;
62 
63 //     System.gc();
64 
65     }
66 }

复制代码

如上所示,当我们执行这段代码的时候并不会引发GC的回收,因为很简单,我的testCase对象还在使用中,生命周期并未结束,因此运行结果如下

但是我们换下面的case2这种写法呢?

复制代码

1 //case 2
2 
3        {
4 
5            byte[] testCase = new byte[10*1024*1024];
6 
7        }
8 
9        System.gc();

复制代码

这种写法,testCase在大括号中生命周期已经结束了,会不会引发GC的呢?我们来看结果:

我们可以看到仍然没有进行回收。那我变通一下,再定义一个变量会怎么样的呢?

复制代码

 1  //case 3
 2 
 3        {
 4 
 5            byte[] testCase = new byte[10*1024*1024];
 6 
 7        }
 8 
 9        int a = 0;
10 
11        System.gc();

复制代码

这下我们貌似看到奇迹了

没错,

JVM做了回收操作,因为JVM在做下面的操作时并没有发现公用的Slot,因此该内存区域被回收。但是我们这样写代码会让很多人感到迷惑,我们应该怎样写才能更好一点让人理解的呢?

复制代码

1  //case 5
2 
3        byte[] testCase = new byte[10*1024*1024];
4 
5        testCase=null;
6 
7        System.gc();

复制代码

无疑,这样写才是最好的,这也是书本effective Java中强调了很多遍的写法,随手置空不用的对象。

我们知道private int a;这么一个语句在一个类中的话他的默认值是0,那么如果是在局部变量中的呢?我们开看这样一段代码:

复制代码

 1 package com.yhj.jvm.byteCode.localVariableInit;
 2 
 3 /**
 4 
 5  * @Described:局部变量拒绝默认初始化
 6 
 7  * @author YHJ create at 2012-2-24 下午08:40:34
 8 
 9  * @FileNmae com.yhj.jvm.byteCode.localVariableInit.LocalVariableInit.java
10 
11  */
12 
13 public class LocalVariableInit {
14 
15  
16 
17     /**
18 
19      * @param args
20 
21      * @Author YHJ create at 2012-2-22 下午05:12:06
22 
23      */
24 
25     @SuppressWarnings("unused")
26 
27     public static void main(String[] args) {
28 
29        int a;
30 
31        System.out.println(a);
32 
33     }
34 
35 } 

复制代码

这段代码的运营结果又是什么的呢?

很多人会回答0.我们来看一下运行结果:

没错,就是报错了,如果你使用的是

Eclipse这种高级一点的IDE的 话,在编译阶段他就会提示你,该变量没有初始化。原因是什么的呢?原因就是,局部变量并没有类实例变量那样的连接过程,前面我们说过,类的加载分为加载、 连接、初始化三个阶段,其中连接氛围验证、准备、解析三个阶段,而验证是确保类加载的正确性、准备是为类的静态变量分配内存,并初始化为默认值、解析是把 类中的符号引用转换为直接引用。而外面的初始化为类的静态变量赋值为正确的值。而局部变量并没有连接的阶段,因此没有赋值为默认值这一阶段,因此必须自己 初始化才能使用。

我们在类的加载中提到类的静态连接过程,但是还有一部分类是需要动态连接的,其中以下是需要动态连接的对象

1、  实例变量(类的变量或者局部变量)

2、  通过其他荣报告期动态注入的变量(IOC)

3、  通过代码注入的对象(void setObj(Object obj))

所有的动态连接都只有准备和解析阶段,没有再次校验(校验发生在连接前类的加载阶段),其中局部变量不会再次引发准备阶段。

前面我们提到JVM的生命周期,在以下四种情况下会引发JVM的生命周期结束

1、  执行了System.exit()方法

2、  程序正常运行结束

3、  程序在执行过程中遇到了异常或者错误导致异常终止

4、  由于操作系统出现错误而导致JVM进程终止

同样,在以下情况下会导致一个方法调用结束

1、  执行引擎遇到了方法返回的字节码指令

2、  执行引擎在执行过程中遇到了未在该方法内捕获的异常

这时候很多人会有一个疑问:当程序返回之后它怎么知道继续在哪里执行?这就用到了我们JVM内存模型中提到了的PC计数器。方法退出相当于当前栈出栈,出栈后主要做了以下事情:

1、  回复上层方法的局部变量表

2、  如果有返回值的话将返回值压入到上层操作数栈

3、  调整PC计数器指向下一条指令

除了以上信息以外,栈帧中还有一些附加信息,如预留一部分内存用于实现一些特殊的功能,如调试信息,远程监控等信息。

接下来我们要说的是方法调用,方法调用并不等于方法执行,方法调用的任务是确定调用方法的版本(调用哪一个方法),在实际过程中有可能发生在加载期间也有可能发生在运行期。Class的编译过程并不包含类似C++的连接过程,只有在类的加载或者运行期才将对应的符号引用修正为真正的直接引用,大大的提升了Java的灵活性,但是也大大增加了Java的复杂性。

在类加载的第二阶段连接的第三阶段解析,这一部分是在编译时就确定下来的,属于编译期可知运行期不可变。在字节码中主要包含以下两种

1、  invokestatic 主要用于调用静态方法,属于绑定类的调用

2、  invokespecial 主要用于调用私有方法,外部不可访问,绑定实例对象

还有一种是在运行时候解析的,只有在运行时才能确定下来的,主要包含以下两方面

1、  invokevirtual 调用虚方法,不确定调用那一个实现类

2、  invokeinterface 调用接口方法,不确定调用哪一个实现类

我们可以通过javap的命令查看对应的字节码文件方法调用的方式,如下图所示

Java

方法在调用过程中,把invokestatic和invokespecial定义为非虚方法的调用,非虚方法的调用都是在编译器已经确定具体要调用哪一个方法,在类的加载阶段就完成了符号引用到直接引用的转换。除了非虚方法以外,还有一种被final修饰的方法,因被final修饰以后调用无法通过其他版本来覆盖,因此被final修饰的方法也是在编译的时候就已知的废墟方法。

除了解析,Java中还有一个概念叫分派,分派是多态的最基本表现形式,可分为单分派、多分派两种;同时分派又可以分为静态分派和动态分派,因此一组合,可以有四种组合方式。其实最本质的体现就是方法的重载和重写。我们来看一个例子

复制代码

 1 package com.yhj.jvm.byteCode.staticDispatch;
 2 
 3 /**
 4 
 5  * @Described:静态分配
 6 
 7  * @author YHJ create at 2012-2-24 下午08:20:06
 8 
 9  * @FileNmae com.yhj.jvm.byteCode.staticDispatch.StaticDispatch.java
10 
11  */
12 
13 public class StaticDispatch {
14 
15  
16 
17     static abstract class Human{};
18 
19     static class Man extends Human{} ;
20 
21     static class Woman extends Human{} ;
22 
23  
24 
25     public void say(Human human) {
26 
27        System.out.println("hi,you are a good human!");
28 
29     }
30 
31     public void say(Man human) {
32 
33        System.out.println("hi,gentleman!");
34 
35     }
36 
37     public void say(Woman human) {
38 
39        System.out.println("hi,yong lady!");
40 
41     }
42 
43     /**
44 
45      * @param args
46 
47      * @Author YHJ create at 2012-2-24 下午08:20:00
48 
49      */
50 
51     public static void main(String[] args) {
52 
53        Human man = new Man();
54 
55        Human woman = new Woman();
56 
57        StaticDispatch dispatch = new StaticDispatch();
58 
59        dispatch.say(man);
60 
61        dispatch.say(woman);
62 
63     }
64 
65 }

复制代码

这个例子的执行结果会是什么呢?我们来看一下结果

和你的预期一致么?这个其实是一个静态分派的杯具,

man和woman两个对象被转型以后,通过特征签名匹配,只能匹配到对应的父类的重载方法,因此导致最终的结构都是执行父类的代码。因为具体的类是在运行期才知道具体是什么类型,而编译器只确定是Human这种类型的数据。

这种写法曾经在我们项目中也发生过一次。如下代码所示

 

 

复制代码

 1 package com.yhj.jvm.byteCode.staticDispatch;
 2 
 3 import java.util.ArrayList;
 4 
 5 import java.util.List;
 6 
 7 /**
 8 
 9  * @Described:蝌蚪网曾经的杯具
10 
11  * @author YHJ create at 2012-2-26 下午09:43:20
12 
13  * @FileNmae com.yhj.jvm.byteCode.staticDispatch.CothurnusInPassport.java
14 
15  */
16 
17 public class CothurnusInPassport {
18 
19     /**
20 
21      * 主函数入口
22 
23      * @param args
24 
25      * @Author YHJ create at 2012-2-26 下午09:48:02
26 
27      */
28 
29     public static void main(String[] args) {
30 
31        List<CothurnusInPassport> inPassports = new ArrayList<CothurnusInPassport>();
32 
33        inPassports.add(new CothurnusInPassport());
34 
35        String xml = XML_Util.createXML(inPassports);
36 
37        System.out.println(xml);
38 
39     }
40 
41 }
42 
43 class XML_Util{
44 
45     public static String createXML(Object obj){
46 
47        return  。。。// ... 通过反射遍历属性 生成对应的XML节点
48 
49     }
50 
51     public static String createXML(List<Object> objs){
52 
53        StringBuilder sb = new StringBuilder();
54 
55        for(Object obj : objs)
56 
57            sb.append(createXML(obj));
58 
59        return new String(sb);
60 
61     }
62 
63 }

复制代码

当时我们项目组写了以恶搞XML_Util的一个类用于生成各种XML数据,其中一个实例传入的参数是Object,一个是一个List类型的数据,如上面代码所示,我的调用结果会执行哪一个的呢?结果大家已经很清楚了,他调用了createXML(Object obj)这个方法,因此生成过程中老是报错,原因很简单,就是因为我叼用的时候泛型 不匹配,进行了隐式的类型转换,因此无法匹配到对应的List《Object》最终调用了createXML(Object obj)这个方法。

下面我们来看一道恶心的面试题,代码如下:

复制代码

 1 package com.yhj.jvm.byteCode.polymorphic;
 2 
 3 import java.io.Serializable;
 4 
 5 /**
 6 
 7  * @Described:重载测试
 8 
 9  * @author YHJ create at 2012-2-24 下午08:41:12
10 
11  * @FileNmae com.yhj.jvm.byteCode.polymorphic.OverLoadTestCase.java
12 
13  */
14 
15 public class OverLoadTestCase {
16 
17     public static void say(Object obj){ System.out.println("Object"); }
18    
19     public static void say(char obj){ System.out.println("char"); }
20 
21     public static void say(int obj){ System.out.println("int"); }
22 
23     public static void say(long obj){ System.out.println("long"); }
24 
25     public static void say(float obj){ System.out.println("float"); }
26 
27     public static void say(double obj){ System.out.println("double"); }
28 
29     public static void say(Character obj){ System.out.println("Character"); }
30 
31     public static void say(Serializable obj){ System.out.println("Serializable"); }
32 
33     public static void say(char... obj){ System.out.println("char..."); }
34 
35     public static void main(String[] args) {
36 
37        OverLoadTestCase.say('a');
38 
39     }
40 
41 }

复制代码

这样的代码会执行什么呢?这个很简单的了,是char,那如果我注释掉char这个方法,再执行呢?是int,继续注释,接下来是什么的呢?大家可以自己测试一下,你会发现这段代码有多么的恶心。

我们接下来再看一段代码:

复制代码

 1 package com.yhj.jvm.byteCode.dynamicDispatch;
 2 
 3 /**
 4 
 5  * @Described:动态分派测试
 6 
 7  * @author YHJ create at 2012-2-26 下午10:05:43
 8 
 9  * @FileNmae com.yhj.jvm.byteCode.dynamicDispatch.DynamicDispatch.java
10 
11  */
12 
13 public class DynamicDispatch {
14 
15     static abstract class Human{
16 
17        public abstract void say();
18 
19     };
20 
21     static class Man extends Human{
22 
23        @Override
24 
25        public void say(){
26 
27            System.out.println("hi,you are a good man!");
28 
29        }
30 
31     } ;
32 
33     static class Woman extends Human{
34 
35        @Override
36 
37        public void say(){
38 
39            System.out.println("hi,young lady!");
40 
41        }
42 
43     } ;
44 
45     //主函数入口
46 
47     public static void main(String[] args) {
48 
49        Human man = new Man();
50 
51        Human woman = new Woman();
52 
53        man.say();
54 
55        woman.say();
56 
57        woman = new Man();
58 
59        woman.say();
60 
61     }
62 
63 }

复制代码

这段代码执行的结果会是什么的呢?这个不用说了吧?企业级的应用经常会使用这些的方法重写,这是动态分配的一个具体体现,也就是说只有运行期才知道具体执行的是哪一个类,在编译期前并不知道会调用哪一个类的这个方法执行。

我们再来看一段代码,这段代码被称为“一个艰难的决定”

复制代码

 1 //动态单分派静态多分派    宗量选择
 2 
 3 package com.yhj.jvm.byteCode.dynamicOneStaticMoreDispatch;
 4 
 5 /**
 6 
 7  * @Described:一个艰难的决定
 8 
 9  * @author YHJ create at 2012-2-24 下午09:23:26
10 
11  * @FileNmae com.yhj.jvm.byteCode.dynamicOneStaticMore.OneHardMind.java
12 
13  */
14 
15 public class OneHardMind {
16     static class QQ{}                //腾讯QQ
17 
18     static class _360{}             //360安全卫士
19 
20     static class QQ2011 extends QQ{} //腾讯QQ2011
21 
22     static class QQ2012 extends QQ{} //腾讯QQ2012
23 
24     //百度
25 
26     static class BaiDu{
27 
28        public static void choose(QQ qq){ System.out.println("BaiDu choose QQ"); }
29 
30        public static void choose(QQ2011 qq){ System.out.println("BaiDu choose QQ2011"); }
31 
32        public static void choose(QQ2012 qq){ System.out.println("BaiDu choose QQ2012"); }
33 
34        public static void choose(_360 _){ System.out.println("BaiDu choose 360 safe"); }
35 
36     }
37 
38     //迅雷
39 
40     static class Thunder{
41 
42        public static void choose(QQ qq){ System.out.println("Thunder choose QQ"); }
43 
44        public static void choose(QQ2011 qq){ System.out.println("Thunder choose QQ2011"); }
45 
46        public static void choose(QQ2012 qq){ System.out.println("Thunder choose QQ2012"); }
47 
48        public static void choose(_360 qq){ System.out.println("Thunder choose 360 safe"); }
49 
50     }
51 
52     //主函数入口
53 
54     @SuppressWarnings("static-access")
55 
56     public static void main(String[] args) {
57 
58        BaiDu baiDu = new BaiDu();
59 
60        Thunder thunder = new Thunder();
61 
62        QQ qq = new QQ();
63 
64        _360 _360_safe = new _360();
65 
66        baiDu.choose(qq);
67 
68        thunder.choose(_360_safe);
69 
70        qq = new QQ2011();
71 
72        baiDu.choose(qq);
73 
74        qq = new QQ2012();
75 
76        baiDu.choose(qq);
77 
78     }
79 }

复制代码

这段代码的执行结果又是什么?现在可以很简单的说出对应的结果了吧!

从这个例子我们可以看出,

Java是静态多分派动态单分派的 同理,C#3.0 、C++也是静态多分配,动态单分派的 C#4.0后引入类型dynamic可以实现动态多分派,sun公司在JSR-292中提出了动态多分派的实现,规划在JDK1.7推出,但是被oracle收购后,截至目前,JDK1.7已经不发布了多个版本,但尚未实现动态多分派。至于动态多分派究竟是怎么样子的?我们可以参考Python的多分派实例。

那虚拟机为什么能够实现不同的类加载不同的方法,什么时候使用静态分派?什么时候又使用动态分派呢?我们把上面的示例用一个图来表示,大家就很清楚了!

 

当 子类有重写父类的方法时,在系统进行解析的时候,子类没有重写的方法则将对应的符号引用解析为父类的方法的直接引用,否则解析为自己的直接引用,因此重写 永远都会指向自己的直接引用,但是重载在解析时并不知道具体的直接引用对象是哪一个?所以只能解析为对应的表象类型的方法。

我们在前面已经提到,新的Java编译器已经不会纯粹的走解释执行之路,在一些情况下还会走编译之路。如下图所示:

我们知道,程序之所以能运行,是因为有指令集,而

JVM主要是基于栈的一个指令集,而还有一部分程序是基于寄存器的指令集,两者有什么区别的呢?

基 于栈的指令集有接入简单、硬件无关性、代码紧凑、栈上分配无需考虑物理的空间分配等优势,但是由于相同的操作需要更多的出入栈操作,因此消耗的内存更大。 而基于寄存器的指令集最大的好处就是指令少,速度快,但是操作相对繁琐。下面我们来看一段代码,看一下同样一段代码在不同引擎下的执行效果有啥不同。

复制代码

 1 public class Demo {
 2 
 3     public static void foo() {
 4 
 5        int a = 1;
 6 
 7        int b = 2;
 8 
 9        int c = (a + b) * 5;
10 
11     }
12 
13 }

复制代码

在Client/Server VM的模式下,我们可以使用javap –verbose ${ClassName}的方式来查看对应的字节码,而基于java的DalvikVM亦可以通过platforms\android-1.6\tools目录中的dx工具查看对应的字节码。具体命令为dx --dex –verbose --dump-to=packageName --dump-method=Demo.foo --verbose-dump Demo.class 。

基于栈的Hotspot的执行过程如下:

基于栈的

DalvikVM执行过程如下所示:

 而基于汇编语言的展示就是这样的了

附:基于JVM的逻辑运算模型如下图所示

因此执行到

JVM上的过程就是下面的形式

 

TensorFlow GPU版本安装步骤-Windows系统 本文由在Windows下安装TensorFlow GPU版本教程-优快云等整理得到。 目录 1、确认显卡是否支持CUDA 1.1 查看显卡信息 打开“设备管理器”,查看显卡信息,如下图所示: 由上图知,本电脑的显卡为NVIDIA Quadro P400. 1.2 查看支持CUDA的显卡 网址:https://developer.nvidia.com/cuda-gpus 经查询可知,该显卡支持CUDA,如下图所示: 2、安装CUDA 2.1 下载CUDA 网址:https://developer.nvi 阅读详情

相关推荐

MATLAB机械臂轨迹规划:在关节空间中生成多项式轨迹以及 jtraj函数(内容超详细讲解)

matlab机器人仿真,关节空间多项式轨迹生成

qq_40969179的博客 1万+

java虚拟机执行过程

虚拟机整体结构图 java虚拟机执行过程 首先由javac前端编译器将源文件转化为字节码文件,字节码文件中有一块区域叫常量池,里面存放着大量的方法信息,是以符号引用的形势存在。而classloader的任务就是将它们加载进运行时数据区的方法区当中,与此同时,它会将符号引用转化为直接引用,并翻译到对应的内存区域中。 ...

m0_55732806的博客 1198

【UE5】三步搞定Pixel Streaming:从零搭建Windows像素流服务

本文详细介绍了如何在Windows平台上快速搭建UE5 Pixel Streaming像素流服务,从插件安装、项目打包到服务启动的全流程操作。通过实战案例和优化配置,帮助开发者实现零客户端配置、跨设备兼容的高性能3D应用流式传输,特别适合建筑可视化和实时协作场景。

weixin_29000991的博客 318

在线.class文件转换.java_Java代码运行的整个过程是怎样运行的?你知道吗?

前几天去面试,面试官问我:Java虚拟机是怎样运行Java字节码的?这个问题问的我哑口无言,虽然工作了5年,但是做的项目基本都是CRUD,所以只想能做好项目就可以了,管他什么底层,跟我有什么关系?这次被打脸了,觉得很丢人,所以花了几天时间把JVM看了一遍,终于把Java虚拟机是怎样运行字节码的搞清楚了!那我们先从HelloWorld 来开始字节码之旅;Java文件是如何变成.class文件的新建一...

weixin_39533361的博客 246

简单初识 Material Point Method(MPM)

简单初识 Material Point Method(MPM):先介绍了Lagrangian和Eulerian,并简单介绍了MPM Method

qq_45776432的博客 7366

即插即用!5分钟为你的SNN模型添加频谱注意力(DCT-SA模块实战)

本文介绍了如何为脉冲神经网络(SNN)快速集成即插即用的DCT-SA频谱注意力模块。该模块利用离散余弦变换(DCT)在频率域自适应加权特征,能有效提升模型对纹理、边缘的感知能力,并在CIFAR10-DVS等数据集上实现分类精度提升与脉冲发放率下降。文章以SpikingJelly框架和ResNet19为例,提供了详细的代码实现、集成步骤及参数调优实战指南。

kotlin6android的博客 609

深度学习与总结JVM专辑(六):JVM字节码执行引擎

加油

左灯右行的爱情 1264

学Simulink——控制执行场景实例:基于Simulink的智能车辆电子稳定控制(ESC)仿真

本文完成了基于 Simulink 的智能车辆电子稳定控制(ESC),实现了:✅ 构建含轮胎非线性的车辆动力学模型✅ 设计滑模横摆稳定性控制器✅ 实现四轮制动力分配逻辑✅ 验证在双移线低附着场景下的卓越稳定性✅ 为主动安全控制系统开发提供完整范式。

xiaoheshang_123的博客 528

JVM特性之八:虚拟机字节码执行引擎

纸上得来终觉浅 绝知此事要躬行 前言:本文参考自 周志明先生的《深入理解Java虚拟机》作学习记录作用,想详细学习java虚拟机的朋友建议买一本书仔细研读。 执行引擎是java虚拟机中最核心的部分之一。 首先,我们要清楚什么是虚拟机,虚拟机是相对于物理机而言的,只不过物理机的执行能力是建立在处理器、硬件、指令集等等层面上的。而虚拟机都是由自己实现的。 执行引擎:输入的字节码文件,处...

BoomMan 1027

SAP_MM_配额安排_PA认证总结

配额安排是企业进行供应商管理的一种方式。通过配额管理,企业可以与多家供应商保持业务往来,以保证某些紧缺原材料的正常供货。此外,企业也可以通过不同的配额比例,提高供应商优化服务、降低价格的积极性。

java_zhong1990的专栏 1021

uniapp - 应用软件在运行时,未见向用户告知权限申请的目的,向用户索取(存储、相机、电话)等权限,不符合华为应用市场审核标准(uniApp开发安卓APP上架应用市场审核被拒绝驳回,详细解决方案)

uniApp应用软件在运行时,未见向用户告知权限申请的目的,向用户索取(存储、相机、电话)等权限,不符合华为应用市场审核标准。uniapp vue2 vue3解决软件在运行时,未见向用户告知权限申请的目的,华为等上架被拒问题,关于华为应用市场上架需要同步告知使用权限的解决方案,uniApp应用软件在运行时,不符合华为应用市场审核标准。解决方案合集!app上架-您的应用在运行时,未同步告知权限申请的使用目的,向用户索取(相机)等权限,不符合华为应用市场审核标准。华为应用市场审核新规(未同步告知权限申请的使用目

🏆 前端领域优质创作者 4163

JVM字节码执行引擎详细解释

字节码执行引擎是JVM内用于解释和执行Java字节码的模块。Java编译器(如javac)将Java源代码编译成字节码,这些字节码被存储在.class文件中。JVM加载这些字节码文件,并使用字节码执行引擎来解释和执行其中的指令。字节码是一种中间表示形式,独立于具体的硬件和操作系统,这使得Java应用程序可以跨平台运行。JVM字节码执行引擎是Java程序执行的核心,它负责解释和执行Java字节码,通过解释执行和即时编译两种方式将字节码转换为机器码执行。

Flying_Fish_roe的博客 1149

Raspberry Pi Pico SDK开发-Timer-定时

RP2040 由 Raspberry Pi 设计,具有双核 Arm Cortex-M0+ 处理器和 264KB 内部 RAM,并支持高达 16MB 的片外闪存。 广泛的灵活 I/O 选项包括 I2C、SPI 和独特的可编程 I/O (PIO)。 本实例将演示如何使用Timer的定时功能。

视觉与物联智能 2040

Java之深入JVM(6) - 字节码执行引擎(转)

前面我们不止一次的提到,Java是一种跨平台的语言,为什么可以跨平台,因为我们编译的结果是中间代码—字节码,而不是机器码,那字节码在整个Java平台扮演着什么样的角色的呢?JDK1.2之前对应的结构图如下所示: 从JDK1.2开始,迫于Java运行始终笔C++慢的压力,JVM的结构也慢慢发生了一些变化,JVM在某些场景下可以操作一定的硬件平台,一些核心的Java库甚至也可以操作底层的硬件平台

songwenbinasdf的专栏 330

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

探索IKVM:Java在.NET平台上的无缝执行与转换

IKVM是一个针对Microsoft .NET平台的Java虚拟机实现,让您无需源代码移植即可在.NET环境中运行Java应用程序和库。它包含了JVM的.NET实现、Java类库的.NET版本、用于将Java字节码转换为.NET中间语言(IL)的工具以及支持Java与.NET互操作的工具。 通过IKVM,您可以: - 在.NET框架或.NET Core上直接执行Java编译的代码 - 将Java

gitblog_00224的博客 1003

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

讲一讲字节码文件

基于jdk1.8,讲一讲字节码文件

kyhoon 387

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

JVM执行引擎

介绍JVM执行引擎。执行引擎是Java虚拟机核心的组成部分之一。虚拟机的执行引擎由软件自行实现,物理机的执行引擎是操作系统层面上。

m0_62946761的博客 6050

《JVM系列》 第七章 -- 字节码执行引擎

执行引擎属于JVM的下层,里面包括: 解释器、及时编译器、垃圾回收器。执行引擎是Java虚拟机核心的组成部分之一。“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现*,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。

龙源IT 的博客 7656

JVM 执行引擎:字节码是如何被执行的

组成部分作用特点程序计数器记录当前执行指令地址每线程独立Java 栈管理方法调用栈帧入栈 / 出栈局部变量表存储参数和局部变量槽位可复用操作数栈存放中间计算结果LIFO 结构帧数据区保存上下文信息含动态连接 / 异常表栈帧重叠优化调用性能节省内存、减少拷贝JVM 执行引擎以线程私有的栈结构为核心,通过程序计数器精确定位字节码指令,依靠局部变量表与操作数栈完成数据存储与运算处理,并借助帧数据区维护方法上下文信息,同时利用栈帧重叠机制优化调用性能。

m0_73341242的博客 1783

深入JVM字节码执行引擎

我们都知道,在当前的Java中(1.0)之后,编译器讲源代码转成字节码,那么字节码如何被执行的呢?这就涉及到了JVM的字节码执行引擎,执行引擎负责具体的代码调用及执行过程。

Floating Cat 1万+

JVM的执行引擎

执行引擎、包括解释器和JIT编译器的介绍

scj1022的博客 2114

深入解析JVM字节码执行引擎

JVM字节码执行引擎核心机制 执行引擎是JVM的核心组件,负责将字节码转换为可执行操作。其核心机制包括: 栈帧管理:每个方法调用创建包含局部变量表、操作数栈等结构的栈帧 指令执行:采用基于栈的架构执行字节码,通过解释器逐条解释执行 JIT优化:对热点代码进行即时编译,使用C1/C2编译器进行多级优化 方法调用:支持静态/动态分派机制,处理不同类型的方法调用 性能优化:运用方法内联、逃逸分析等关键技术提升执行效率 执行引擎通过解释执行与即时编译相结合的方式,在保证跨平台性的同时优化性能表现。

2301_80215285的博客 1169

JVM学习-字节码执行引擎

JVM-字节码执行引擎

疼了也不哭的博客 1068

java 虚拟机(jvm)-10-JVM 字节码执行引擎

Java虚拟机的执行引擎 输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。 本章主要是从概念模型的角度讲解虚拟机的方法调用和字节码执行。 帧栈 帧栈是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。 每一个帧栈中都包括以下信息:局部变量表(Local Varable Table)、操作数栈(Operand Stack)、动态连接(D...

1万+

JVM:字节码执行引擎

JVM 的字节码执行引擎是 Java 程序运行的核心,字节码指令集定义了程序的执行逻辑,解释执行和编译执行的协同工作机制则在保证程序快速启动的同时,提高了程序的执行效率。深入理解字节码执行引擎的工作原理,有助于我们优化 Java 程序的性能,编写更加高效的代码。在实际开发中,我们可以通过合理的代码设计和 JVM 参数配置,充分发挥字节码执行引擎的优势,提升 Java 应用的整体性能。

jukuya的博客 1096
上一篇: C语言的函数调用的过程
下一篇: jvm的解释器和编译器是如何进行协作执行代码的
蓝猫_虹
博客等级 码龄12年 49粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值