JAVA内存区域

##1、运行时数据区
     java运行时数据区可以分为以下几个部分,程序计数器,虚拟机栈,本地方法栈,堆,和堆中的方法区。如下图所示:
这里写图片描述
其中程序计数器、本地方法栈和虚拟机栈是线程私有的,方法区和堆是线程共享的,其中方法区是堆的逻辑组成部分。

###1.1、程序计数器
     java中的指令都是用一个字节表示的,所以叫字节码指令。**程序计数器指向当前线程字节码指令执行的行号,**特殊情况,如果正在执行的是java方法,那么是字节码的行号,如果是native方法,那么程序计数器为空。

###1.2、虚拟机栈
     介绍虚拟机栈之前先对栈帧做个介绍,**栈帧是虚拟机栈的组成元素,用来支持虚拟机方法调用和方法执行的数据结构,**一个方法包含使用一个栈帧,栈帧中包含了四个主要组成部分,**局部变量表,操作数栈,动态链接,方法出口。**结构图如下:
这里写图片描述
**局部变量表中包含了方法中需要用到的变量,在java程序编译成class文件的过程中就已经确定了哪个方法有多少个局部变量,局部变量表的容量以slot为最小单位,**一般情况下一个slot是32位的,能够存放32位及以下的变量,**对局部变量表的访问时通过索引的方式访问的,**索引值的范围是0到slot的最大的数量-1,如果执行的是实例方法(非static),那么编号0代表的就是this,当前对象的引用,其余按照方法总变量的顺序进行序号的排序。这里做一个局部变量表的通常结构描述图:
这里写图片描述
对于这个方法在局部变量的中的存储结构如下:
这里写图片描述
然后是操作数栈,操作数栈的深度也在编译成class文件的时候确定了,**用来存放方法中指令写入的数据,**字节码指令往操作数栈中进行写入和读取操作也叫做入栈和出栈。这里仍然用上面一个代码来画出程序运行过程中程序计数器,操作数栈和局部变量表的关系。
这里写图片描述
然后是动态连接,动态连接是方法中调用其他方法是通过对对应方法的引用的调用实现的,持有方法的引用并通过这个引用调用对应的方法这个过程称为动态连接。在类加载中类中的方法会被存入方法区,方法的引用也在方法区中,在运行过程中,栈帧会从方法区中获取对应方法的引用并对方法进行调用。
最后是方法返回地址,当一个方法开始执行后,如果调用了其他的方法,会将此时的程序计数器的地址也就是方法的返回地址给保存起来,从而再方法调用完毕后能够回到调用方法的位置,如果是正常退出,会有有返回值返回给调用者,如果是异常退出则不会,当程序退出时可能进行的操作有:恢复上层方法的局部变量表和操作数栈,将返回值压如操作数栈中,程序计数器指向下一条指令。

###1.3、本地方法栈
     本地方法栈和虚拟机栈的数据 结构基本是一样的,只是上面的存储的是java方法的数据,这里存储的是native方法的数据。

###1.4、方法区
     方法区是堆的一个逻辑区域,用来存放类的描述信息、静态变量、常量、编译后的代码等。首先是最能够理解的编译后的代码,也就是所说的class文件,因为在虚拟机进行类加载时候的第一步就会将class文件以字节流的方式进行加载,当进行了class文件格式验证可用后就会存储到方法区,所以这就是编译后的代码部分,然后我们来看class文件的组成部分,就能理解为什么这个区域还存放了类信息、静态变量、常量等数据了。class文件时jvm虚拟机能够解释执行或者编译执行的文件,是一组以字节为基础单位的文件,class文件采用类似于C语言中结构体类似的结构来存储数据,**结构体中只有两种数据类型,无符号数和表,且数据之间没有间隔,**全是数据,无符号数由u1、u2、u4、u8组成,表由无符号数和表组成。**这是文件的数据格式。接下来是文件的组成部分:**前面四个字节是魔数用于进行身份识别,确定是否是class文件,**接着是4个字节 是版本号,**确定是否是虚拟机支持的版本,**接下来是常量池,**常量池存放了字面量和符号引用,其中字面量是各种常量如字符串、常量值、类名、接口名、字段名、方法名等,符号引用是字段和方法以及类的描述符,通过符号引用可以定位到这些类,方法,和字段。**常量池过了是访问标志,**用来标志类或者接口的访问信息,如是否是public类,是否声明为final等等。**访问标志过了是类索引、父类索引、接口索引集合,**这几个是用来确定类有哪个父类和实现了哪些接口。**索引集合过了就是字段表集合,**这个用来描述类中声明的变量,注意这里是描述声明变量的各种信息。最后是方法表集合,同上面一样,这个是用来描述类中定义的方法的各种信息。还有一个就是属性表集合,这个属性表集合不是一个单独的区域而是字段表、方法表都包含的集合,用来描述某些场景专有的信息,例如方法表中的Code属性就存储了方法中java代码被编译过后的字节码指令,以及局部变量表的大小和操作数栈的深度等信息。所以看到这里就基本上知道为什么方法区中存放了类信息、静态变量、常量等信息了,因为class文件被加载进了方法区,而这些东西都是class文件中所包含的东西。

###1.5、堆
     前面几个区域介绍完了,最后就这个对区域,也是最简单的区域,主要就放了java中的对象实例。

##2、虚拟机对象
     前面对java运行时数据区进行了详细的介绍,在介绍的过程中基本也对每个区域中数据如何存放进行了介绍,但是堆上对象的创建还没介绍,所以这里按以下三点进行介绍。

###2.1、对象的创建
     对象的创建主要要有一下几个步骤,**首先看能不能通过指令的参数在常量池中找到对应类的符号引用,****然后通过符号引用找到类后再判断这个类是否被加载、连接和初始化了,如果这几步有没完成的步骤,那先完成对应的步骤。然后在堆中给对象分配空间,分配内存可以采用CAS操作或者预先给线程分配内存缓冲池的方法,这个内存分配不会冲突,然后在对对象中的值进行初始化,**最后再对对象头进行设置,如hashcode、偏向锁、元数据指针等信息进行设置。

###2.2、对象的内存布局
     对象在内存中的存储是8字节对齐的也就是说对象存放的地址是8的倍数,由三部分组成,对象头,对象实例,对齐填充。其中对象头包含两个字或者三个字,在我的锁的博客中对对象头有详细的介绍,这里不做详细介绍,一个MarkWord用来存储对象的hashcode,分代年龄,锁信息等,一个用来存放对象元数据的指针。对象实例就是对象里面元素的存放,对齐填充就是使8字节对齐的,可以不要。

###2.3、对象的访问定位
     对象的访问定位分为两种,一种是直接访问,引用就是对象的地址,另一种是句柄访问,引用是句柄的地址,而句柄存放了对象的地址,前者的好处是速度更快,效率更高,后者是对象被移动时,引用的地址不用变。一般通过第一种方法进行访问。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值