JVM 全名是Java Virtual Machine
它是负责跨平台的已编译的一小段代码,这里的平台包括硬件和操作系统。
JAVA对JVM,它只解析特定格式的文件class,你可以用任何语言去写代码,只要按照class的语法生成文件,JVM都可以解析。
JVM和java一样有两种类型变量
原始类型
引用类型
运行时数据:
堆-JVM启动的时候,就已经分配出一块内存给堆了。堆里面的信息可以在线程之间共享
栈-JVM的每创建一个进程,就会创建一个私有的栈给这个进程。当线程的生命周周期结束了,这个栈也释放了。如果用到native的方法,那么JVM还有创建一个native stack
每个非native线程都有一个PC(process count)
PC会注册当前运行的方法地址,用来定位每个方法的位置,可以记录线程的执行轨迹。比如多个线程抢占CPU,当一个线程失去CPU的使用权,当它获得资源的,就是用PC回到上次执行的。
JVM stack的分配
用户可以自己配置,可以是固定的,也可是的动态分配的。Stack不需要连续的内存。Stack是每个线程私有的,它存储局部变量和结果。每个线程都有一个stack。stack里面包含的信息叫做frame。帧里面包含了一个本地变量数组,操作数stack,symbolic linking。
如果超过stack准许的最大值,Java会抛出StackOverflowError
如果stack是动态分配的,但是物理机器没有足够的内存可用,则抛
OutOfMemoryError
堆和non-heap:
堆是JVM启动时候就已经分配,每个线程可以共享的内存,它也不需要连续的存储块。它包含了一些class的信息,构造,方法,字段等。它包含了下面信
---方法区
它也是属于non-head(非堆)里面的内容,它包含了class的结构,运行时的常量池,字段,方法数据,还包括了具体的代码。这个内存里面的数据可以不用GC。class的实例分配在真正的堆里面。
--- 常量池
它属于方法区里面的信息。包含了原始常量和引用常量。
Frames
farme被push到stack里面。每一个执行一个方法都会创建一个frame,它包含局部变量数组,操作数栈,指向当前class的常量池的引用和方法的返回值。
Frames里面有一个当前frame。Frame是和方法生命周期共存的。
Local variable array每个位置只能存储一个32位的变量,如果是long或者double,就必须占用2个位置
Local variable array如果是从class里面调用方法,方法参数从0位开始
如果是instance方法,则从1 index开始,0留给this引用
例如JVM 用istore_1把操作栈顶部的一个int值存入到local variable arry里面,index是1.
Operand Stacks
操作数栈
Jvm指令用operand stacks里面的数值做运算,然后将结果再push到stack里面。比如用aload_0,把local variable arry的index为0存储的值,push到stack里面。为下面的其他操作指令做好准备。
Long和double占stack 2个depth位。
Dynamic linking
链接到class的常量池
这张图可以体现上面的JVM architecture: