当前位置: 首页 > 科技观察

JVM执行程序+内存模型交互详解

时间:2023-03-11 21:56:52 科技观察

什么是JVMjvm是一个虚构的机器,但是是在真实的电脑上模拟各种功能来实现的。jvm包含一组字节码指令集,一组寄存器,一个栈,一个垃圾回收堆,一个存储方法字段。JVM使Java程序无需任何修改即可在多个平台上运行,只需要生成代码在Java虚拟机上运行即可。JVM在执行字节码时,最终将字节码解释成机器指令执行。JDK、JRE、JVM是什么关系“JDK:”是开发者用来编译和调试程序的开发包。JDK也需要JAVA程序,需要运行在JRE上。“JRE:”Java平台,所有的Java程序都必须在JRE环境下运行。“JVM:”它是JRE的一部分,JRE是一种虚构的计算器,通过在实际计算机上模拟计算机功能来实现。JVM执行一个程序的过程一个Java文件从编码到执行需要经历几个阶段:1.编译阶段:首先将.java文件通过Javac编译成.class文件。2.加载阶段:然后通过类加载器将.class文件加载到JVM的内存中。3.解释阶段:类字节码被字节码解释器解析成系统可以识别的指令代码。4、执行阶段:向硬件设备发送指令代码进行操作。《详细说说每个阶段》编译阶段****类编译阶段的主要目的是将源代码文件编译成JVM可以解析的class文件。这个阶段会经历句法的词法分析和语义分析。类文件包含哪些内容?“幻数:”这是.class文件头中的四个字节。它的作用是定义识别标准。只有符合标准,才能被JVM解释。"版本号:"编译class文件的JDK版本号。这些版本向后兼容。“常量池:”常量池中的信息主要包括字面量、基本类型常量、符号引用(全限定、方法名和描述符等)。“AccessFlags:”类是否是接口、注解、枚举或模块。“类索引:”类的索引、父类的索引、接口的索引集合,用于确定类的继承和实现关系。“字段表集合:”这个用来描述接口或者类中声明的信息,比如(public/private/protected)。“方法表集合:”方法表集合类似于字段表集合,即用于保存方法的相关信息,包括方法的名称“属性表集合:”这包括指令代码类、方法和实例变量。加载阶段加载阶段主要是将.class文件加载到JVM内存中。这个阶段有加载、连接、初始化三个过程。“加载:”加载阶段就是将类中的信息读入内存。首先,它通过类的全限定名读取本类的二进制流,然后将字节流中描述静态结构的信息转换为方法区中的运行时数据结构。在加载阶段结束时,会在Java堆上生成一个可以代表这个类的java.lang.class对象作为这个对象的访问入口。“连接:”在这个连接阶段,会校验类的信息,然后为类变量分配内存空间,赋默认值。首先是验证该字节是否符合JVM对类内容的规范,然后为静态变量分配内存空间,最后分析并把符号引用转换为直接引用,因为这里的类信息已经在内存中了。所以引用对象会被替换成对象在内存中的实际地址。《初始化:》初始化阶段主要是执行初始化静态块的内容,真正给静态变量赋值。解释阶段Interpretation该阶段在代码执行期间触发。当一个类的某个方法开始执行时,首先以这个类的对象为入口,找到对应的字节码信息,然后通过解释器将字节码解释成指令码。在最初的执行过程图中,有两个解析器。解释器有字节解释器和编译器JIT。通常,运行代码时会使用默认的字节码解释器来解析指令。只有当某个方法是热方法时,连编译器都会保存热方法的命令代码,以便下次执行时无需重复解析就可以进行优化。在执行阶段,操作系统从解释器中获取指令代码,通过调用系统的硬件来执行最终的程序指令。Java内存之间的交互是如何实现Java主内存和工作内存之间特定的交互协议的呢?也就是说,一个变量如何从主内存复制到工作内存?这样的细节在Java内存模型中有八个操作,每个操作都是原子的,不可分割的。1."lock(锁):"加锁这个操作作用于主存中的变量,它会将一个变量标记为线程独占状态2、"unlock(解锁):"作用于主存中的变量,放一个锁定的变量被释放,释放的变量可以被其他线程锁定。3、“读取(read):”作用于主存的变量,将一个变量从主存调到线程的工作内存,供后续加载使用。4.“加载(load):”作用于工作内存的变量,它将读操作从主内存中获取的变量值放入工作内存的变量副本中。5、“use(使用):”作用于工作内存中的一个变量,将工作内存中的一个变量值传递给执行引擎6、“assign(赋值):”作用于工作内存中的一个变量,传递7."store(storage):"作用于工作内存的变量,将工作内存中的一个变量值传送到主内存中,以供后续使用写操作。8.“写(write):”作用于主存的变量,它将存储操作从工作存中的一个变量的值转移到主存的变量中。以上八种内存交互操作必须满足规则“第一”,其中read和load、store和write操作不允许单独出现,即不允许从主存中读取一个变量,buttheworkingmemoryisnotaccepted,或者从工作内存发起回写,但是主存不接受。“其次”,不允许一个线程丢弃它最近一次的assign操作,即变量在工作内存中发生变化后,必须将变化同步回主内存。“第三”,不允许线程无缘无故(不发生assign操作)将数据从线程的工作内存同步回主内存。“第四”,一个新的变量只能在主存中“诞生”,不允许在工作内存中直接使用一个未初始化(加载或赋值)的变量。换句话说,就是在一个变量上实现use和store操作之前,必须先进行assign和load操作。“第五”,一个变量只允许一个线程同时对其进行加锁,但加锁操作可以由同一个线程重复多次。回解锁。《第六》如果对一个变量进行了锁操作,工作内存中这个变量的值就会被清空。在执行引擎使用这个变量之前,需要重新执行加载或赋值操作来初始化变量的值。“第七”,如果一个变量事先没有被lock操作锁定过,则不允许对其进行unlock操作,也不允许解锁被其他线程锁定的变量。《第八》在对一个变量执行解锁操作之前,必须将该变量同步回主存(执行store、write操作)。volatile变量的特殊规则当一个变量被定义为volatile时,这个变量对所有线程的可见性得到保证。这里所说的可见性是指当一个线程修改这个变量的值时,新的值是给其他线程的。马上就可以知道,普通变量是做不到这一点的,因为普通变量的取值需要在线程传入的时候通过主存来完成。Java内存模型中定义volatile变量的特殊规则是:(1)线程对变量的load和read操作需要是连续的,同时出现,并且要求必须在workingmemory中。从主内存中刷新最新值,这也确保其他线程对变量所做的修改是可见的。(2)线程对变量的store和write操作需要是连续的,同时发生。要求是它们必须在工作记忆中。每次修改变量后,必须立即将它们同步回主存,以保证其他线程可以看到自己。对变量V所做的更改。