虚拟机在java堆中对象分配、布局和访问的过程

简介: java虚拟机读书笔记 对象的分配、布局、访问

二、虚拟机在java堆中对象分配、布局和访问的过程
  • 一、 对象的创建
    • 1、从java程序,new指令开始,从虚拟机来看,则是判断类是否被加载;
    • 2、类加载通过后,有两个问题:
      • 一、内存分配,
        • 对象所需内存的大小在类加载完成后就可以完全确定,为对象分配空间的任务等于把一块确定大小的内存从Java堆中划分出来。
        • 两种方法:
          • 指针碰撞
          • 空闲列表
        • 分配方式的选择取决于:java堆是否规整;Java堆是否规整取决于:所采用的垃圾收集器是否带有压缩整理功能。
        • 例子:
          • 在使用Serial、ParNew等带有Compact过程的收集器时,系统采用分配算法为:指针碰撞;
          • 使用CMS,基于 Mark-Sweep算法的收集器时,系统采用分配算法为:空闲列表。
      • 二、对象创建的线程安全问题
        • 问题描述
          • 对象创建在虚拟机中的行为非常频繁,即使只是修改一个指针所指向的位置,在并发情况下也并不是线程安全的,有可能出现正在给对象A分配
          • 内存,指针还没有修改,对象B又同时使用了原来的指针来分配内存的情况。
        • 解决方法,有两种:
          • 1 对分配空间的动作进行同步处理;
            • 实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;
            • CAS(比较与交换,Compare and swap)是一种有名的无锁算法。(ConcurrentHashMap也用到了此算法)
          • 2 本地线程分配缓冲
            • 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在java堆中预先分配一小块内存,称为本地线程分配缓冲(Tlab)。
            • 虚拟机是否使用Tlab,可以通过-XX:+/-UseTlab参数来设定
    • 3、对象内存分配完成后,虚拟机把内存空间初始化
      • 虚拟机将分配到的内存空间都初始化为零值(不包括对象头),如果使用Tlab,初始化操作可以提前至Tlab分配时进行。
      • 目的:
        • 保证了对象的实例字段在java代码中可以不赋初始值就可以直接使用,程序能访问到这些字段的数据类型所对应的的零值。
    • 4、修饰对象
      • 虚拟机对对象进行必要的设置。其实是对象头。
      • 对象头中包括:对象的哈希码、对象的Gc分代年龄、此对象是哪个类的实例、类的元数据信息的指示等;
      • 根据虚拟机当前的运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。
    • 5、对象产生
      • 从虚拟机的角度,一个新的对象已经产生。
      • 从java程序的角度,对象创建才刚刚开始,init方法还没有执行,所有的字段都为零。
        • 一般来说(由字节码中是否跟随invokespecial指令所决定),执行new 指令之后会接着执行方法,
        • 把对象按照程序员的意愿进行初始化,这样一个真正可用的对象产生。
  • 二、 对象的内存布局
    • 对象在内存中布局分配分为三个部分
      • 对象头
      • 实例数据
      • 对齐填充
    • 1 、对象头
      • 如图:
        746053c1-0024-4667-80f9-6cace6fa994e-5210562.jpg
      • 第一部分
        • 用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,
      • 第二部分
        • 类型指针,即对象指向它的类元素数据的指针,虚拟机通过该指针确定对象的实例是哪个类。
    • 2 、实例数据
      • 对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。
      • 包括父类继承的,子类定义的;
      • 存儲順序: 虚拟机分配策略参数和字段在java源码中定义的顺序 ;
      • hotSpot虚拟机默认的分配策略为longs/doubles、ints、 shorts/chars、bytes/booleans、oops(Ordinary Object Pointers),
      • 相同宽度的字段被分配到一起。在这个前提下,父类中定义的变量会出现在子类之前。
    • 3 、对齐填充
      • 不是必须存在的,只是占位符的作用。
      • 因为对象的大小必须是8字节的整数倍。对象头部分正好是8字节的倍数,当对象实例数据部分没有对齐时,通过对齐填充补全。
  • 三、 访问
    • 访问方式有2个,句柄和指针:
      • 句柄访问
        f502ca94-6fc3-4bb3-ac78-8f7c7c52d34c-5210562.jpg
        • 存储位置:java 堆中划分一块内存作为句柄池,reference中存储的就是对象的句柄地址;
        • 包含信息:对象实例数据与类型数据各自的具体地址信息。
      • 指针访问
        9a55bcb9-2a0b-4f82-8031-84036ee1b25f-5210562.jpg
        • reference 存储的直接就是对象地址。
        • 问题: 考虑java堆对象的布局中存放访问类型数据的相关信息。
    • 两种方法的优劣:
      • 句柄
        • reference中存储的是稳定的句柄地址,对象被移动时,只改变句柄中的实例数据指针,而reference本身不需要修改。(在垃圾收集时移动对象时普遍的)
      • 指针
        • 速度更快,节省了一次指针定位的时间开销。--由于对象的访问在java非常频繁。(积少成多)
    • Sun HotSpot 采用第二种方式

相关文章
|
3天前
|
缓存 前端开发 Java
【前端学java】复习巩固-Java中的对象比较(15)
【8月更文挑战第11天】Java中的对象比较
11 1
【前端学java】复习巩固-Java中的对象比较(15)
|
2天前
|
Java API 开发者
|
1天前
|
存储 设计模式 Java
在 Java 中创建多个对象
【8月更文挑战第17天】
6 0
|
3天前
|
Java Spring 容器
Java SpringBoot 中,动态执行 bean 对象中的方法
Java SpringBoot 中,动态执行 bean 对象中的方法
11 0
|
存储 缓存 Java
《深入理解Java虚拟机》读书笔记
《深入理解Java虚拟机》是整个Java图书领域公认的经典著作和超级畅销书,全书共分为五大部分,围绕内存管理、执行子系统、程序编译与优化、高效并发等核心主题对JVM进行了全面而深入的分析,深刻揭示了JVM的工作原理。本文就是读者对于本书阅读后的读书笔记,和大家一起分享。
3383 0
|
存储 运维 监控
《深入理解Java虚拟机》学习笔记
第2章 垃圾收集器与内存分配策略 1.Java虚拟机在执行java程序时会把它所管理的内存会分为若干个不同的数据区域, 这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是在以来用户线程的启动和结束而建立和销毁。
5043 0
|
2月前
|
Unix Linux 虚拟化
虚拟机VMware知识积累
虚拟机VMware知识积累
|
26天前
|
存储 SQL 运维
服务器数据恢复—Isilon存储误删除vmware虚拟机的数据恢复案例
Isilon存储使用的是分布式文件系统OneFS。在Isilon存储集群里面每个节点均为单一的OneFS文件系统,所以Isilon存储在进行横向扩展的同时不会影响数据的正常使用。Isilon存储集群所有节点提供相同的功能,节点与节点之间没有主备之分。当用户向Isilon存储集群中存储文件时,OneFS文件系统层面将文件划分为128K的片段分别存放到不同的节点中,而节点层面将128K的片段分成8K的小片段分别存放到节点的不同硬盘中。用户文件的Indoe信息、目录项及数据MAP则会分别存储在所有节点中,这样可以确保用户不管从哪个节点都可以访问到所有数据。Isilon存储在初始化时会让用户选择相应的
49 12