写点什么

jvm(二) 内存管理与虚拟机执行子系统

作者:想要飞的猪
  • 2022-11-17
    广东
  • 本文字数:1476 字

    阅读完需:约 5 分钟

对象的创建(出数组,Class 对象)


1、当 jvm 遇到一个 new 指令时,首先检查是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析、初始化过,没有则执行相应的类加载过程。


2、加载过后分配内存(类在加载完成时就已经确定占用多大的内存,分配内存等是把堆中的内存划分出),有两种分配方式(使用那种方式取决于使用的垃圾收集器是否有整理功能):


2.1、指针碰撞:内存比较规整,被使用的和空闲的内存分别放两边,中间有个指针,分配时只需要把指针向空闲边移动;
2.2、空闲列表:虚拟机维护一个列表,记录那些内存是可以分配的,然后再足够大的空间划分给对象实例;
复制代码


3、对象分配内存安全性问题


  再多线程的情况下 可能出现正在给A对象分配内存时,指针还未来的及修改,对象B同时又使用了原来的指针来分配内存的情况,解决方法:
3.1、分配内存空间的动作同步处理----> 实际上jvm时采用CAS配上失败重试的机制实现
3.2、另一种是把内存分配的动作按照线程划分在不同的区域,即每个线程在Java堆中预先分配一块内存,称为本地线程分配缓冲(THAB),只有本地缓冲使用完了,在外面申请内存空间时才同步锁定;
复制代码


对象的内存布局


1、在 hotSpot 虚拟机中,对象在堆中存储布局可以划分为三部分,对象头、实例数据、对其填充


2、对象头:对象头部分包含两类信息。


2.1、第一类时用于存储对象自身的运行时数据,如hashCode 、GC分代年龄、锁状态标志、线程持有的所,偏向线程ID、偏向时间戳等等;这部分长度在32位和64位虚拟机(未开启指针压缩)中分别为32比特和64比特,称为Mark Word;
Mark wod 是一个有着都动态定义的数据结构,根据不同的状态复用自己的空间。如:无锁时 25位表示 hashCode ,4位表示分代年龄,2位表示锁标识,1位固定标识位0(标识是否Wie偏向锁)
2.2、类型指针:即对象指向他的类型元数据的指针,长度也是32/64(未开启指针压缩)
3.2、数组长度(只有对象是数组时才有)32/64位
复制代码


对象的访问


    对象的定位时通过栈上的引用reference 数据来操作堆上的对象的,但是虚拟机规范中并没有指定用神方式去定位;一般有两种:
1、使用句柄:Java堆中要划分出来一块内存作为句柄,reference中存储的就是对象句柄的地址,而句柄中就包含了对象的实例数据与类型数据的地址信息,所以使用句柄的时候需要二次寻址;
2、使用直接指针:栈中的指针直接指向对象实例数据,这是就要考虑如何防止类型数据信息了(HotSpot 是对象头中有指针指向类型对象)
复制代码


虚拟机执行子系统


1、Class 文件结构


1.1、魔数与Class文件版本
复制代码


  • 魔数:Class 文件的头 4 个字节 0xCAFEBABE ,它是唯一确定这个文件是否位 Class 文件,很多文件都会使用魔数来标明文件格式,而不是使用后缀,因为后缀是可以修改的。

  • 版本号: Java 版本号是 45 开始,在魔数的 后 4 位表示版本号,5、6 字节表示的是此版本号,7、8 字节表示的是主版本号 如下

  • 被模块导出或者是开放的包

  • 类或者是接口的全限定名

  • 方法名称和描述符

  • 方法句柄和方法类型

  • 动态调用点和动态常量

  • 1.4、字段表集合:用于描述接口或者是类中声明的变量,Java 语言中的子墩包括类级变量以及实例变量,可以修饰字段的包括 作用于(public,private、protected)、是实例变量还是类变量(static)、可变性(final)、并发可见性(volatile)、是否可序列化(transient)、字段数据类型、字段名称,各个修饰符都可以用 01 标识,要么有这个修饰符那么没有这个修饰符,所以使用固定的长度来标识;而字段类型于名称是无法固定,只能医用常量池中的常量来描述;

  • 1.5、方法表集合、属性表集合 于字段表集合类似,只是使用的集合不同思想相同。

用户头像

还未添加个人签名 2020-06-05 加入

还未添加个人简介

评论

发布
暂无评论
jvm(二)内存管理与虚拟机执行子系统_java对象内存布局_想要飞的猪_InfoQ写作社区