JVM(Java Virtual Machine)
原始类型
整数类型为:
byte,其值为8位带符号的二进制补码整数(-到
-1),并且其默认值为零
short,其值为16位带符号的二进制补码整数(-到
-1),并且其默认值为零
int,其值为32位带符号的二进制补码整数(-到
-1),并且其默认值为零
long,其值为64位带符号的二进制补码整数(-到
),并且其默认值为零
char,其值为16位无符号整数,表示基本多语言平面中的Unicode代码点,并以UTF-16编码,其默认值为空代码点(’\u0000’)。
浮点类型为:
float,其值是float值集的元素,或者(在受支持的情况下)float-extended-exponent值集的元素,并且其默认值为正零
double,其值是双精度值集或受支持的双扩展指数值集的元素,并且其默认值为正零
内存模型
- JVM分为五个区域:虚拟机栈、本地方法栈、方法区、堆、程序计数器
- 虚拟机栈、本地方法栈、程序计数器为线程私有,方法区和堆为线程共享区。
- 占用内存大小不同,一般情况下堆最大,存放“对象”,程序计数器较小
堆(Heap)
- 堆的GC操作采用分代收集算法
- 堆区分了新生代和老年代
- 新生代又分为:Eden空间、From Survivor(S0)空间、To Survivor(S1)空间。
无法再扩展时,将会抛出OutOfMemoryError异常,垃圾收集器就是根据GC算法,收集堆上对象所占用的内存空间
方法区(Method Area)
方法区与Java堆一样,是各个线程共享的区域,它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译(JIT)后的代码等数据。
由于程序中所有的线程共享一个方法区,所以访问方法区的信息必须确保线程是安全的。如果有两个线程同时去加载一个类,那么只能有一个线程被允许去加载这个类,另一个必须等待。
在程序运行时,方法区的大小是可以改变的,程序在运行时可以扩展。同时,方法区里面的对象也可以被垃圾回收,但条件非常严苛,必须在该类没有任何引用的情况下才能被GC回收。
程序计数器(Program Counter Register)
占用内存较小,线程私有。它是唯一没有OutOfMemoryError异常的区域。
字节码解释器工作时就是通过改变计数器的值来选取下一条字节码指令。其中,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器来完成。
JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,为了各条线程之间的切换后计数器能恢复到正确的执行位置,所以每条线程都会有一个独立的程序计数器。
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie方法,这个计数器值则为空(Undefined)。
虚拟机栈(JVM Stacks)
线程私有,生命周期与线程相同
描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表(局部变量表需要的内存在编译期间就确定了所以在方法运行期间不会改变大小),操作数栈,动态链接,方法出口等信息。每一个方法从调用至出栈的过程,就对应着栈帧在虚拟机中从入栈到出栈的过程。
本地方法栈(Native Method Stacks)
虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈是为虚拟机使用到的Native方法服务。
类加载
将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
类的加载过程
加载、连接、初始化、使用、和卸载五个阶段
1、加载
- 通过一个类的全限定名来获取其定义的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
2、链接
- 验证:确保被加载的类的正确性;
- 准备:为类的静态变量分配内存,并将其初始化为默认值;
- 解析:把类中的符号引用转换为直接引用。
符号引用就是一组符号来描述目标,可以是任何字面量。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
3、初始化
类变量进行初始值设定有两种方式:
1)声明类变量是指定初始值。
2)使用静态代码块为类变量指定初始值。
类的初始化步骤或JVM初始化的步骤如下:
1)如果这个类还没有被加载和链接,那先进行加载和链接 ;
2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口);
3 ) 假如类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句。
类加载器
默认情况下有三种类加载器(引导类加载器,扩展类加载器,应用类加载器),我们也可以自定义类加载器。
应用程序的每一个类都由ClassLoader加载,java类是被动态的加载到内存,java的一大特点,也称为运行时绑定。
双亲委派模型
JVM类加载时采用双亲委派机制。双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载。保证在复杂的类依赖关系中,类加载的顺序性、唯一性和安全性。
还没有评论,来说两句吧...