JVM组成架构
Java之所以可以实现跨平台运行,是因为运行在JVM虚拟机上,JVM屏蔽了底层系统的不同,为Java字节码文件构造了一个统一的运行环境。
其组成结构如下:
类加载器将对应.class 文件装在到方法区。
当进入一个方法时,创建方法栈针,放到Java栈中顶部,局部变量也在栈中。
如果方法中有New class, 放入到堆中。创建的对象都放入堆中。
程序计数寄存器,记录执行到哪一行指令。
指令是java自己的指令,需要执行引擎将java的指令变成依赖的系统对应的指令。
java不同环境下,执行引擎不同,是本地编译出来的。
.class字节码文件,在不同到平台上是一样的。执行引擎,把.class变成本地代码执行。
Java字节码
Java可以在不同平台上运行,因为不同平台都是在执行.class文件。
字节码执行流程:
字节码指令给执行引擎,如果编译过会直接执行。若没有编译过,看方法调用计数器,如果次数超过阈值,则编译字节码,编译成可执行指令,放入code cache;如果没有超过,给解释器,解释器将字节码解释成多行本地指令,交给本地方法执行。
这里注意,“执行编译后的机器码”来源于“code cache”。
字节码文件编译过程:
类似于Sql的编译过程。源文件词法分析得到token流。通过语法分析,变成语法树。对语法树进行语义分析,生成字节码。生成的字节码,为虚拟机可执行的指令。
类加载器
字节码通过类加载器加载到JVM的方法区。JVM使用双亲委托模型,即,低层次的当前类加载器,不能覆盖更高层次类加载器已经加载的类。
堆&栈
类似于操作系统的堆栈。JVM有唯一的堆。每个线程有独立的栈。对象在堆中分片,但是引用在栈中
方法区&程序计数器
方法区存放加载进来的类字节码。程序运行方法区中的指令时,每个线程有自己的程序计数器,记录自己执行到的指令。
线程工作内存 & volatile
Java内存模型规定所有的变量都是存在主存当中,每个线程都有自己的工作内存。线程对变量的所有操作都必须在工作内存中进行,而不能直接对主存进行操作。线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行。
volatile 修饰的变量,写一定会刷到主内存,读一定从主内存中读。
保证多CPU情况下,多线程对同一变量可见。不过要注意,volatile只是保证对所有线程可见,但是线程是不安全的。只保证可见性,不保证线程安全性。
网友评论