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

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 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 采用第二种方式

相关文章
|
9月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
1061 157
|
11月前
|
缓存 安全 Java
Java反射机制:动态操作类与对象
Java反射机制是运行时动态操作类与对象的强大工具,支持获取类信息、动态创建实例、调用方法、访问字段等。它在框架开发、依赖注入、动态代理等方面有广泛应用,但也存在性能开销和安全风险。本文详解反射核心API、实战案例及性能优化策略,助你掌握Java动态编程精髓。
|
11月前
|
存储 人工智能 JavaScript
Java从作用域到对象高级应用​
本内容详细讲解了JavaScript中的作用域类型(函数作用域、块作用域、全局作用域)、作用域链、垃圾回收机制、闭包、变量提升、函数参数、数组方法、内置构造函数、对象高级知识、原型链、对象赋值、深浅拷贝、递归、异常处理及this指向等内容,全面覆盖JS核心概念与编程技巧。
133 0
|
Java 算法 搜索推荐
Java实现堆的封装,进行插入,调整,删除堆顶以完成堆排序实例
简介 堆对于排序算法是一个比较常用的数据结构,下面我就使用Java语言来实现这一算法 首先,我们需要知道堆的数据结构的形式,其实就是一个特殊的二叉树。但是这个二叉树有一定的特点,除了是完全二叉树以外,对于最大堆而言,堆顶元素的值是最大的,而且对于堆的每一个子树也是一个小一号的最大堆;同样对于最小堆,性质相反就可以了。
951 0
|
9月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
427 1
|
9月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
392 1
|
10月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
433 0
|
10月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
610 16
|
11月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。