首页 > 编程语言 >Java对象的生命周期

Java对象的生命周期

时间:2023-07-25 15:04:35浏览次数:42  
标签:存储 生命周期 Java 对象 GC 内存 数组 指针

前言

有出生那么肯定就有死亡, 在 java中, 对象的诞生是我们开发人员 new出来的, 对象的使用也是我们开发人员进行操作的, 但是对象的创建你了解过吗? 接下来就让我们一起去揭开对象生命周期的神秘面纱

1. 对象的创建流程

快速入门之简单讲讲, 本节也按照创建流程来展开讲解

  • 首先我们开始 new一个对象
  • 进行常量池检查 看能否在常量池中定位到这个类的符号引用, 定位不到则加载类 看是否加载过这个类, 没加载过则加载类
  • 分配内存空间 指针碰撞: GC不带压缩功能, Serial和ParNew 空闲列表: GC带压缩功能, CMS
  • 内存空间初始化为零值: 保证了对象的实例字段在 java代码中科院不赋初始值就直接使用, 程序能访问到这些字段的数据类型所对应的零值
  • 必要信息设置 对象类的元数据 对象的哈希码 GC分代年龄 -> 对象头
  • init()

Java对象的生命周期_老年代

类的加载可以看这篇文章: JVM之类加载器 - 掘金 (juejin.cn)

2 对象的内存分配方式

内存的方法有两种

  • 指针碰撞 假设 Java堆中的内存是绝对规整的, 所有用过的内存放一边, 未使用内存放另一边, 中间边界线就可以类比为指针, 内存分配就是把指针向未分配的区域挪一段与对象大小相等的距离, 这就是指针碰撞

Java对象的生命周期_句柄_02

  • 空闲列表 如果 Java堆中的内存不是很规整的, 已使用和未使用的内存就会相互交错, 这个时候就要维护一个列表来记录所有已使用和未使用的内存块, 在分配内存时从列表找到一块足够大的空间划分给对象实例, 并更新内存列表

Java对象的生命周期_句柄_03

分配方法

说明

收集器

指针碰撞

内存地址是连续的(新生代)

Serial和 ParNew收集器

空闲列表

内存地址不连续(老年代)

CMS收集器和 Mark-Sweep收集器

2.1 内存分配的安全问题

通过上一小节我们知道了对象的内存分配方式, 但是我们想这样一个场景: 线程A 去给对象分配内存的过程中, 此时指针未修改, 线程B 也去请求了同一块内存地址, 这个时候就出现了内存抢占, 也就是线程安全问题

对于这种问题, 在JVM中有两种解决办法:

  • CAS: CAS是乐观锁的一种实现方式, 虚拟机采用 CAS配合失败重试的机制来保证操作的原子性
  • TLAB本地线程分配缓冲: 为每一个线程预先分配一块内存, 在给对象分配内训时直接在自己这块私有内幕才能中进行分配, 当新的对象大于剩余内存或者内存耗尽之后, 在分配新的内存

因为内存分配这是一个高并发的操作, CAS就显得效率低下了

可以通过设置-XX:+/-UseTLAB 参数来指定是否开启TLAB分配(默认启动)

2.2 对象进入老年代

  • 新生代对象: 新生代对象大多数默认会进入到Eden区
  • 对象进入老年代的四种方式: 存活年龄太大, 超过阈值之后会转入到老年区(默认15, 参数: -XX:MaxTenuringThreshold=15) Hotspot遍历所有对象时,按照年龄从小到大对其所占用的大小进行累积,当累积的某个年龄大小超过了survivor区的一半时,取这个年龄和MaxTenuringThreshold中更小的一个值,作为新的晋升年龄阈值 大对象直接进入老年代 Serial和 ParNew收集器 例如超长的字符串和数组 GC后, Survivor区放不下所有的对象

2.3 内存担保机制

当新生代无法分配内存时, 我们想把新生代的老对象转移到老年代, 然后把新对象放到腾空的新生代, 这种机制我们称之为内存担保

  • GC之前, 判断老年代最大可用连续内存是否大于新生代所有对象总大小 大于: GC是安全的 不大于: 查看HandlePromotionFailure设置值是否允许担保失败 允许: 检查老年代最大可用连续空间是否大于历次晋升老年代对象的平均大小 大于: 尝试进行一次 Minor GC(此次GC有风险) 不大于: 进行 Full GC 不允许: 进行 Full GC

Java对象的生命周期_老年代_04

3 对象的内存布局

在堆内存中, 一个对象的的存储布局可以分为三个区域:

  • 对象头: 对象头分为两部分 存储对象自身的运行时数据 哈希吗 GC分代年龄 锁状态标准 ... 类型指针: 类元素局的指针, 虚拟机通过这个指针来确定这个对象是哪个类的实例
  • 实例数据: 存储对象真正的有效信息, 例如: 非静态变量也会存入堆空间
  • 对齐填充: 不是必然存在的, 也没有特别的含义. JVM内对象都采用8byte对齐, 不够8byte整数倍的就需要通过对齐填充来补全

3.1 对象头

  • 对象头Header:Java对象头占8byte。如果是数组则占12byte。在 JVM中数据需要数组长度size来记录数组长度, 占用4byte
  • 标记字段Mark Word: 用于存储对象自身的运行时数据,它是synchronized实现轻量级锁和偏向锁的关键。 默认存储:对象HashCode、GC分代年龄、锁状态等等信息。 为了节省空间,也会随着锁标志位的变化,存储数据发生变化。下面画图解释
  • 类型指针KlassPoint: 是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例 开启指针压缩存储空间4byte,不开启8byte。 JDK1.6+默认开启
  • 数组长度(只有数组对象才有):如果对象是数组,则记录数组长度,占4个byte,如果对象不是数组则不存在。
  • 对齐填充:保证数组的大小永远是8byte的整数倍。

3.2 对象头大小

对象头信息是与对象自身定义的数据无关的额外存储成本。考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构,以便在极小的空间内,尽量多的存储数据,它会根据对象的状态复用自己的存储空间,也就是说,Mark Word会随着程序的运行发生变化,变化状态如下(JDK1.8)。

Java对象的生命周期_数组_05

基本数据类型和包装类的内存占用情况:

Java对象的生命周期_数组_06

3.3 对象头总结图示

Java对象的生命周期_句柄_07

图片来自于5分钟,带你理解Java对象的内存布局

4 如何访问一个对象

对象的访问方式由虚拟机俩决定, 目前主流的访问方式有以下两种

  • 句柄 使用句柄的话, java堆中会专门划分出一块内存来作为句柄池, reference中存储对象句柄的地址, 句柄中包含了对象实例数据与对象类型数据各自的具体地址信息
  • 直接指针: 访问速度快, 节省了一次指针定位的开销 直接访问, reference中存储的就是对象的地址, 节省了一次指针定位的开销

标签:存储,生命周期,Java,对象,GC,内存,数组,指针
From: https://blog.51cto.com/u_16173732/6845446

相关文章

  • 手机登录注册 java
    手机登录注册Java实现流程1.简介在这篇文章中,我将向你介绍如何通过使用Java实现手机登录和注册功能。手机登录注册功能是很多应用程序的基础功能之一,让用户能够通过手机号码进行身份验证和访问应用程序。我将按照以下步骤详细说明实现过程。2.实现步骤步骤描述1......
  • 手机播放器java版
    手机播放器java版手机播放器是一款广受欢迎的应用程序,用于在移动设备上播放音频和视频文件。本文将介绍如何使用Java编写一个简单的手机播放器应用程序。前提条件在开始编写手机播放器应用程序之前,我们需要先安装Java开发环境(JDK),并熟悉面向对象编程的基本概念。创建项目首先,我......
  • 生成2位随机数 java
    生成2位随机数Java实现方法简介本文将介绍如何使用Java生成一个两位数的随机数。首先,我们将以表格的形式展示整个实现过程的步骤。然后,我们将详细说明每个步骤需要做的事情,并提供相应的代码和注释。实现步骤以下表格展示了生成两位随机数的实现步骤:步骤描述步骤......
  • Java开发要学哪些知识,看这篇就够了!
    Java开发是计算机行业中的一个重要领域,随着互联网的普及和应用,其发展也越来越快速,也越来越重要。那么Java学习顺序与方法有哪些?Java开发的技能点和知识点非常丰富,对于初学者来说,学习顺序和方法的选择非常关键。那么,Java学习顺序与方法有哪些?学习Java开发,需要有清晰的学习路线......
  • Java学习路线,Java后端开发需要学什么?
    在计算机领域中,Java作为非常流行的的编程语言之一,是很多后端开发工作的主力语言之一。如果你想学习Java后端开发,那么小编在这里为你提供一些学习路线和建议,希望可以让你尽快进入这个领域。 第一步,你必须了解Java语言的基本知识,包括语法、流程控制、数据类型、循环和类等。可以......
  • 银河麒麟桌面安装java
    安装JavaJava是一种广泛应用于开发各种应用程序的编程语言。在Linux系统中,使用银河麒麟桌面环境,可以通过几个简单的步骤来安装Java。本文将介绍如何在银河麒麟桌面上安装Java,并附带代码示例。步骤一:检查是否已安装Java在开始安装Java之前,我们首先需要检查系统中是否已经安装了Ja......
  • 【HarmonyOS】实现从视频提取音频并保存到pcm文件功能(API6 Java)
    ​ 【关键字】视频提取类Extractor、视频编解码、保存pcm文件 【写在前面】在使用API6开发HarmonyOS应用时,通常会开发一些音视频媒体功能,这里介绍如何从视频中提取音频保存到pcm文件功能,生成pcm音频文件后,就可使用音频播放类AudioRenderer进行播放了。这里主要介绍从视频提......
  • Java中抽象类和接口的区别
    一.抽象类定义上来看,被abstract关键字修饰的类称为抽象类。被abstract关键字修饰的方法称为抽象方法。当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类.例:[public|protected]abstractclassT{Stringname;intage;......
  • 【Java入门】小白快速入门 Java(一)
    ......
  • java~IDE工具技巧
    代码折叠操作:选中代码,按ctrl+alt+t,之后选择region代码环绕折叠后的效果spring代码格式化每个项目添加统一的依赖包<plugin><groupId>io.spring.javaformat</groupId><artifactId>spring-javaformat-maven-plugin</artifactId><version>0.0.35</version&g......