1、JVM内存模型
Java内存模型是指Java虚拟机的内存模型,我们来看下Java内存模型的图片:
其中,在JAVA的JVM调优中,我们JAVA程序员需要重点关注的,首先是堆,我们看下堆内存的内存模型:
2、类的加载过程
(1)、加载
通过一个类的全限定名获取该类的二进制流,将该二进制流中的静态存储结构转化为方法去运行时数据结构,在内存中生成该类的Class对象,作为该类的数据访问入口。
(2)、验证
文件格式验证:验证字节流是否符合Class文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型
元数据验证:对字节码描述的信息进行语义分析,如这个类中是否有父类,是否集成了不被继承的类等
字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等
符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行
(3)、准备
准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在Java堆中
(4)、解析
该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后
(5)、初始化
初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码
类加载的补充、、、
1、类加载检查: 虚拟机遇到一条new指令的时候,首先去检查这个指令的参数是否能够在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否被加载,解析和初始化过,如果没有,那么必须执行相应的类加载过程
2、分配内存: 在类加载检查通过后,接下来虚拟机将为新生对象分配内存,对象所需内存的大小在类加载完之后便可以完全确定,为对象分配空间的任务相同于一块确定大小的内存在Java堆中划分出来
这个步骤有两个问题:1、如何划分内存 2、在并发情况下,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同事使用了原来的指针来分配内存的情况
划分内存的方法: 使用CAS的方法保证每次操作都是原子操作
3、初始化: 内存分配完成之后,虚拟机需要将分配到的内存空间都初始化为零值,如果使用TLAB,这一工作过程也可以提前至TLAB分配时进行,这一步操作保证了对象的实例字段在JAVA代码中可以不赋初始值可以直接使用
4、设置对象头: 初始化零值之后,虚拟机要对对象进行赋值,例如这个对象是哪个类的实例,如果才能找到类的类源数据信息,对象的哈希吗、对象的GC分代年龄、这些东西都放置在对象头ObjectHeader中
对象在内存中的存储布局可以分为3块区域:对象头、实例数据、对其填充位,HotSpot虚拟机的对象头包括两部分信息,第一部分用于存储对象自身运行的数据,如哈希吗、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等、对象的另一部分是类型指针,即对象指向它的类元数据指针,虚拟机通过指针来确定这个对象是哪个类的实例
5、执行方法: 执行方法,即对象按照开发人员的意思进行初始化,对应到语言层面上讲。就是为属性赋值,执行构造方法