Java虚拟机——运行时数据区与对象内存布局

运行时数据区

程序计数器

记录线程当前正在执行的虚拟机字节码指令的地址;如果正在执行的是本地方法,则计数器值为空(Undefined)。它是程序控制流的指示器,分支,循环,跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。

Java虚拟机栈

它描述了Java方法执行的线程内存模型:每个方法 被调用时,Java虚拟机都会同步创建一个 栈帧,该栈帧用于存放该方法的局部变量表、操作数栈、动态连接、方法出口等信息。方法的调用与完成对应着栈帧的入栈和出栈。

在局部变量表中,存放的是:

  • java虚拟机基本数据类型
  • 对象引用
  • returnAddress类型(指向了一条虚拟机字节码指令的地址)

局部变量表的存储空间以 局部变量槽 来表示,double和long类型的数据会占用2个变量槽,其余的类型占用1个变量槽。

本地方法栈

当线程调用本地方法时,该存储空间为本地方法提供服务(存储局部变量等)

Java 堆

堆只有一个任务:存放对象实例。

方法区

存储已经被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

运行时常量池

class文件除了有类的版本、字段、方法、接口等描述信息外,还有一项信息:常量池表,该部分内容将在类加载后存放到方法区的运行时常量池中。

HotSpot虚拟机对象的创建与管理

创建

对象需要的内存大小在类加载完成后就完全确定了,分配内存有两种方式:

  • 指针碰撞(Bump The pointer):假设Java堆内存是完全规整的,所有使用过的内存在一边,空闲的内存在另一边,它们之间由一个指针分开。当为对象分配空间时,只需要将该指针向空闲空间方向移动对象大小的距离。
  • 空闲列表(Free List):如果Java堆中的内存并不规则,使用过的和空闲的混在一起,那么虚拟机就需要维护一个列表,该列表记录了空闲内存。当为对象分配空间时,从列表中找到一块足够大的内存块分配给对象,并更新列表。

根据垃圾回收器是否带有空间压缩整理(Compact)的能力来觉得使用哪种分配方式。

对象内存布局

对象在堆中的存储布局可以分为三类:

  • 对象头

    对象头又由两类数据组成:

    • 对象自身运行时数据:
    • 类型指针:对象指向它的类型元数据的指针
  • 实例数据: 程序代码里面所定义的各种类型的字段内容。这部分的顺序受虚拟机分配策略参数(-XX:FieldsAllocationStyle)和字段在源码中定义的顺序影响。HotSpot默认的顺序为:long/doubles,ints,chats/shorts,bytes/booleans,oops(Ordinary Object Pointers, OOP)。相同宽度的字段总是被分配在一起

  • 对齐填充:并不必然存在,也没有任何意义,只做填充用,因为HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8 字节的整数倍。

对象访问定位

Java程序会通过栈上的引用数据来操作对上的具体对象,如何访问对象由虚拟机来觉得,以下是两种主流的方式:

  • 使用句柄:

  • 直接指针访问:

两种方式各有好处,使用句柄,当对象实例位置发生变化时,只需要修改句柄的指针,reference中存储的是稳定句柄指针,但是要访问到实例需要两次指针定位。直接指针则恰恰相反。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值