首页 > 编程语言 >图文深入理解java对象从创建到回收都经历了什么

图文深入理解java对象从创建到回收都经历了什么

时间:2024-10-15 19:48:48浏览次数:3  
标签:初始化 java 对象 回收 JVM Java 图文

1. 前言:

每个java对象都是有生命周期的,就像一个人的生命一样,从孕育到出生到成长变老最后由归于自然。笔者认为,Java对象的整个生命周期可以分为两个大的阶段:即创建阶段和运行阶段(包含对象的回收和消亡)。本篇将会图文深入介绍java对象的整个生命过程。
一般人平时看到java其实只是冰山的一角–java世界的冰上部分,冰下的java世界其实更精彩。
在这里插入图片描述

1.java对象的创建阶段

在Java中,对象的创建是一个复杂但有序的过程,涉及多个步骤和底层的JVM(Java虚拟机)运作。java对象的创建过程近似于下图,详细过程如下:
在这里插入图片描述

1. 类的加载

其实,在创建对象之前,JVM需要确保类已经被加载、链接和初始化,但这个过程属于对象的孕育阶段,就像一个人在母体一样,所以也是算作对象的创建阶段:

  1. 加载(Loading):将类的字节码从文件系统中读取到内存中。
  2. 链接(Linking),又可分为三个阶段:
    验证(Verification):确保字节码是合法的,不会违反Java语言的语义规则。
    准备(Preparation):为类的静态变量分配内存并设置为默认值(例如,int为0,引用类型为null)。
    解析(Resolution):将符号引用转换为直接引用(例如,将方法名转换为方法地址)。
  3. 初始化(Initialization):执行类的初始化代码,包括静态变量的赋值和静态块的执行。

2. 分配内存

在这里插入图片描述

在类加载完成后,JVM会在堆内存中为对象分配空间。实际运作过程如下:

  1. 判断是否需要线程安全:如果多个线程同时创建同一个类的对象,JVM需要确保内存分配的原子性。这可以通过两种方式实现:
  2. 使用同步机制:确保每次只有一个线程可以分配内存。
  3. 使用本地线程分配缓冲区(TLAB,Thread Local Allocation Buffers):每个线程在堆内存中预先分配一块私有空间,用于对象的分配。这样可以减少同步的开销。
  4. 分配内存:在堆中分配内存空间,具体方式取决于JVM使用的垃圾回收器。例如,在使用Serial GC时,直接分配在Eden区;在使用G1 GC时,根据对象的预期存活时间选择适当的区域。

3. 初始化内存

分配的内存空间初始化为零(基本数据类型,对象引用类型初始化为null)。这一步确保了对象的字段在构造方法执行之前处于确定的状态。

4. 设置对象头

每个对象在内存中都有一个对象头(Object Header),用于存储对象的一些元数据,包括:
哈希码(Hash Code):用于快速查找对象,例如在HashMap中。
GC分代年龄(GC Age):记录对象在垃圾回收过程中经过的次数,用于决定对象是否晋升到老年代。
锁状态标志(Lock Status):记录对象是否被锁定,以及锁的类型(轻量级锁、重量级锁等)。
类元数据指针(Class Metadata Pointer):指向对象的类元数据,用于在运行时访问类信息。

5. 执行构造方法

在对象内存分配和初始化之后,JVM会调用对象的构造方法来完成对象的初始化。构造方法中的代码会设置对象的字段值并执行其他初始化逻辑。

6. 返回引用

构造方法执行完毕后,JVM会将新创建对象的引用返回给调用者。此时,对象已经完全创建并可以使用了。

java对象的运行阶段

在这里插入图片描述

  1. 对象的使用(Usage)
    一旦对象被创建并初始化,它就可以被应用程序使用。对象通过其引用变量进行访问和操作。演示如下:
public class Person {  
    static String period = "GESTATION";  
    int instanceVar;  
    static {  
        // 静态初始化块  
        System.out.println("这是我的孕育阶段");  
    }  
  
    public void say() {  
        System.out.println("我就是我,不一样的烟火!");  
    }  
  
    public Person() {  
        // 构造函数  
        System.out.println("构造函数被执行");  
        this.instanceVar = 0;  
    }  
  
    public static void main(String[] args) {  
        Person person = new Person();  
        System.out.println("我出生了");  
        // 可以调用person的say方法  
        person.say();  
    }  
}
  1. 对象的垃圾回收(Garbage Collection)
    当对象不再被应用程序使用时,JVM的垃圾回收器(Garbage Collector, GC)会自动回收该对象所占用的内存空间。Java使用自动垃圾回收机制,程序员不需要手动释放内存。垃圾回收的判断依据主要是对象的可达性(Reachability),即对象是否从根集合(Root Set)可达。常见的可达性状态包括:
    可达(Reachable):对象可以从根集合直接或通过其他可达对象间接到达。
    可复活(Resurrectable):对象的所有引用都被释放,但在某个时间点它可能再次变为可达。
    不可达(Unreachable):对象既不是可达的,也不是可复活的。这些对象会被垃圾回收器回收。
  2. 对象的终结(Finalization)
    Java提供了一个finalize()方法,允许对象在垃圾回收之前执行清理操作。然而,需要注意的是,finalize()方法并不保证会被及时调用,也不应该被用作主要的清理机制。从Java 9开始,finalize()方法已被弃用,建议使用java.lang.ref.Cleaner和java.lang.ref.PhantomReference来替代。
  3. 对象的销毁(Destruction)
    对象的销毁是指对象所占用的内存空间被垃圾回收器回收的过程。在Java中,对象的销毁是自动进行的,程序员无法直接控制。

本篇完结。
码字不易,宝贵经验分享不易,请各位支持原创,转载注明出处,多多关注作者,家人们的点赞和关注是我笔耕不辍的动力。

标签:初始化,java,对象,回收,JVM,Java,图文
From: https://blog.csdn.net/qq_45732829/article/details/142870192

相关文章

  • Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
    什么是变量?在Java里,变量就是一个“可变的小盒子”,你可以随时改变它里面的数据。就像你有一个存钱罐,可以随时往里面放钱、取钱,今天装100块,明天变成200块,完全没问题。变量的定义:当你要定义一个变量时,你要告诉Java两个信息:这个“盒子”是用来装什么类型的数据(也就是数据类......
  • JAVA基础笔记1(变量与运算符+基本数据类型)
    目录一.开发工具1.快捷键常用二.HelloWorld案例:输出:心形三:变量与运算符3.1关键字3.2 标识符(identifier)3.3变量3.30变量的概念:3.31变量类型3.32引用数据类型:   类:class   数组:array   接口:interface   枚举:enum   注解:annotation   ......
  • Java毕业设计 基于SpringBoot和Vue游戏商城网站
    Java毕业设计基于SpringBoot和Vue游戏商城网站这篇博文将介绍一个基于SpringBoot框架和Vue开发的游戏商城网站,适合用于Java毕业设计。功能介绍首页图片轮播游戏推荐游戏分类游戏详情添加购物车立即购买积分兑换评论收藏游戏论坛发布帖子游戏资讯......
  • Java中多线程的学习
    Java多线程学习总结目录Java多线程学习总结什么是进程什么是线程进程与线程的区别地址空间资源占用健壮性执行过程并发与资源消耗创建线程方式一:继承Thread类,并重写run()方法方式二:实现Runnable接口,并实现run()方法线程的状态线程暂停执行条件线程优先级多线程多线......
  • 四,Java面向对象
    Java面向对象:封装与构造方法笔记封装private关键字:概述:private是Java中的访问修饰符,用于隐藏类的内部细节,只通过公共方法(public)提供访问。特点:使用private修饰的成员变量或方法只能在同一个类内部访问,不能被类的外部直接访问。使用方式:成员变量:this.成员变量名,......
  • 前端原型链:探索 JavaScript 中的继承奥秘
    一、引言在前端开发领域,JavaScript是一门广泛应用的编程语言。而原型链作为JavaScript中一个重要的概念,对于理解JavaScript的面向对象特性和实现继承机制起着关键作用。它不仅影响着代码的组织和复用方式,还决定了对象之间的关系和属性访问规则。本文将深入探讨前端原型链......
  • 讨论java有基础类型,为什么还要有封装类型呢?两者之间的比较方式?
    java有哪些基础类型boolean/1byte/8char/16short/16int/32float/32long/64double/64java为什么有基础类型,为什么还要有封装类型呢?举个例子吧,Character和char的区别是在于char只是存了个数据,而Character的区别在于他带有了一系列操作该数据的方法好处是什么呢?......
  • Java 初学 day 08
    java081、Abstract关键字java为了表示现实生活中抽象的概念集合,提供了一个关键字给我们使用:abstractabstract抽象的可以修饰类,修饰成员方法1.被abstract修饰的类是抽象类,抽象类不能被实例化2.被abstract修饰的方法是抽象方法,抽象方法不能有大括号实现3.在抽......
  • java 不建议使用stack
    Java不建议使用Stack的原因和替代方案在Java编程中,Stack类通常用于处理数据结构中的堆栈实现。然而,随着Java的发展,越来越多的开发者开始质疑是否应该继续使用Stack类。本文将探讨不建议使用Stack的原因,示例代码,以及推荐的替代方案。Stack类简介在Java中,Stack是一种后进先出(LIFO......
  • Java在for循环中修改集合
    前天看到一篇文章什么?for循环也会出问题?,里面涉及到在for循环中修改集合,想起来自己刚入行的时候就碰到过类似的问题,于是复现了一下文章中的问题,并试验了其它在循环中修改集合的方法。底层原理参考什么?for循环也会出问题?这篇文章的分析1.在fori中修改集合在fori中修改集合,不会......