《深入理解Java虚拟机》 Java对象的生命周期
- Java虚拟机运行时数据区
- 方法区:存储 类信息、常量、静态变量、即使编译器编译后的代码等数据,也有别名叫做非堆。 方法区其中有包含有 运行时常量池,用于存放编译期生成的各种字面量和符号引用。其中,可通过String.intern()方法将字符串放入运行时常量池中。
 - 堆:存储的是类实例对象,数组。 JVM 所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。 从内存回收的角度来看,由于现在收集器基本都采用 分代收集算法,所以堆可以细分为 新生代 和老年代;再细分 新生代可以分为:Eden空间,From Survivor空间和To Survivor空间等。
 - 虚拟机栈:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程。
 - 本地方法栈: 本地方法栈服务于虚拟机执行Native方法服务。作用与虚拟机栈相似。
 - 程序计数器:程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。每条线程都需要有一个独立的程序计数器
 
 - Java类加载机制
- 装载
- 加载方式:
- 从本地系统中直接加载
 - 通过网络下载class文件
 - 从归档文件中加载class文件
 - 从专有数据库中提取class文件
 - 将Java源文件 动态编译为class文件,也就是运行时计算而成
 - 从加密文件中获取
 
 
 - 加载方式:
 - 连接
- 验证
 - 验证java版本号,文件格式,元数据校验(是否有父类,是否继承了final类等java 语法)字节码验证(运行检查,栈数据类型和操作码操作参数是否吻合)
 - 准备
- private static final int a =1; constantValue 通知虚拟机生成常量赋值,不需要开辟内存。 基于final static 修饰的 基本数据类型和String起作用
 
 - 解析
- 将常量池内的符号引用转变成直接引用
 
 
 - 初始化
- 初始化什么时候被触发? 类 主动使用到的时候1 创建类的实例,也就是new2 访问某个类或者接口的静态变量,给该静态变量赋值3 调用类的静态方法4.反射 (class.forname("..."))5.初始化某个类的子类,则其父类也会被初始化6.java 虚拟机启动时被标明为启动类的类(如springboot启动类)
 
 - 使用
 - 卸载
- 1.该类所有的实例都已经被回收,即java堆中不存在该类的任何实例2. 加载该类的classloader 已经被回收3. 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法
 
 
 - 装载
 - 类加载器
- 类加载器的加载特性:
- 全盘类型机制
 - 父类委托
 - 缓存机制
 
 
加载完之后开始使用类,此时需要运行时数据区- PC寄存器
 - 本地方法栈
 - 虚拟机栈
 - 堆:装载的时候,存储所有class实例 空间不足抛出oom
 - 方法区 :
 - 线程共享区域,class结构信息,运行时常量池,方法,构造器,方法数据,静态定义
 - 内存不够时,抛出OOM
 - 运行时常量池(在方法区中):包含字符串常量池
 

- 动态链接:符号引用变成直接引用会改变这个动态链接属性
 
 - Java对象内存布局
- Java对象内存分为三部分: 对象头,实例数据,对齐填充
 
 
- 对象头
- Mark Word : 哈希码,分代年龄,线程持有的锁,偏向锁ID,偏向时间戳,锁状态,还有1bit的占位符
 - class Pointer: 指的是类型指针,对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
 
 实例数据
- 对象真正存储的有效信息,代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。这部分的存储顺序会受到虚拟机分配策略参数和字段在Java远吗中定义顺序的影响。HotSpot虚拟机默认的分配策略为longs/doubles、ints、shorts/chars、bytes/booleans、oops,从分配策略中可以看出,先攻宽度的字段总是被分配到一起的。在满足这个前提条件的情况下,在父类中定义的变量会出现在子类之前。
 
- 对齐填充
- HotSpot VM 要求对象大小必须是8字节的整数倍
 
 
- 对象头
 - 对象定位方式:
- 建立对象是为了使用对象,我们的Java程序需要通过栈上的reference数据来操作对上的具体对象。目前主流的访问方式有两种:使用句柄和直接指针两种方式
 

使用句柄访问的最大好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾回收)时,只会改变句柄中的实例数据指针,而reference本身不修改。
- 使用直接指针访问方式的好处是速度更快,节省了中间转发访问的步骤。
 
 - Java对象的生命周期
- 创建阶段
 - 应用阶段
 - 不可见阶段
 - 不可达阶段
 - 收集阶段
 - 终结阶段
 - 空间重分配阶段
 
- 对象创建过程:
 
- 判断对象是否已经“死”了的算法有两种: 
-   引用计数算法: 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的情况,都是不可能再被使用的。
- 引用计数算法的缺陷就是它很难解决对象之间相互循环引用的问题
 
 - 可达性分析算法:通过一系列的成为“GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链,当一个对象到GC roots没有任何引用链相连时,则证明此对象是不可用的。
 - 在Java中,可作为GC roots的对象包括下面几种:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
 - 方法区中类静态属性引用的对象
 - 方法区中常量引用的对象
 - 本地方法栈中JNI(即一般说的Native方法)引用的对象。
 
 
 -   引用计数算法: 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的情况,都是不可能再被使用的。
 引用分类:
强引用:只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象
- 软引用:对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收
 - 弱引用: 被弱引用关联的对象只能生存到下一次GC发生之前。
 - 虚引用: 为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
 
- 垃圾收集算法
-   标记-清除算法
-   不足:
- 效率问题:标记和清除两个过程的效率不高
 - 空间问题:标记清除后会产生大量不连续的内存碎片,碎片太多导致以后再程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
 
 
 -   不足:
 - 复制算法:将可用的内存按容量划分大小相等的凉快,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,简单高效。
- 不足:
- 当对象存活率较高时,要进行较多的复制操作,效率会降低。
 
 
 - 不足:
 - 标记-整理算法:标记过程仍然与”标记-清除算法一样,后续让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
 - 分代收集算法:
 - 这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适合的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成。而老年代中因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-清理”或者“标记-整理”算法来进行回收。
 
 -   标记-清除算法
 
 
《深入理解Java虚拟机》 Java对象的生命周期的更多相关文章
- [原创]java WEB学习笔记47:Servlet 监听器简介, ServletContext(Application 对象), HttpSession (Session 对象), HttpServletRequest (request 对象) 监听器,利用listener理解 三个对象的生命周期
		
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
 - Java 对象的生命周期
		
Java对象的生命周期 在Java中,对象的生命周期包含下面几个阶段: 1. 创建阶段(Created) 2. 应用阶段(In Use) 3. 不可见阶段(Invisib ...
 - 【转载】Java对象的生命周期
		
Java对象的生命周期 在Java中,对象的生命周期包括以下几个阶段: 1. 创建阶段(Created) 2. 应用阶段(In Use) 3. 不可见阶段(Invisib ...
 - Java虚拟机(三)垃圾标记算法与Java对象的生命周期
		
前言 这一节我们来简单的介绍垃圾收集器,并学习垃圾标记的算法:引用计数算法和根搜索算法,为了更好的理解根搜索算法,会在文章的最后介绍Java对象在虚拟机中的生命周期. 1.垃圾收集器概述 垃圾收集器( ...
 - 深入Java虚拟机--判断对象存活状态
		
程序计数器,虚拟机栈和本地方法栈 首先我们先来看下垃圾回收中不会管理到的内存区域,在Java虚拟机的运行时数据区我们可以看到,程序计数器,虚拟机栈,本地方法栈这三个地方是比较特别的.这个三个部分的特点 ...
 - Java对象的生命周期与作用域的讨论(转)
		
导读: Java对象的生命周期大致包括三个阶段:对象的创建,对象的使用,对象的清除.因此,对象的生命周期长度可用如下的表达式表示:T = T1 + T2 +T3.其中T1表示对象的创建时间,T2表示对 ...
 - Hibernate中Java对象的生命周期
		
一个对象的出生源于我们的一个new操作,当我们使用new语句创建一个对象,这个对象的生命周期就开始了,当我们不在有任何引用变量引用它,这个对象就的生命就此结束,它占用的内存就可以被JVM的垃圾回收器回 ...
 - [原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定
		
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
 - java之hibernate之session中对象的生命周期
		
1. session是用来执行对象的crud操作,并且session是对象事务工厂.session是线程级别的,所以生命周期比较短. 2.session中对象的生命周期图: 3.session中对象的 ...
 
随机推荐
- 第15.13节 PyQt(Python+Qt)入门学习:Qt Designer的Spacers部件详解
			
一. 引言 在Designer的部件栏中,有两种类型的Spacers部件,下图中上面布局中为一个水平间隔部件(按钮1和按钮2之间的部件),下面布局中为一个垂直间隔部件(按钮3和4之间),如图: 这两种 ...
 - 派大星的烦恼MISC
			
挺有意思的杂项,python将二进制转图片的时候出现的图片不像二维码,想看题解的时候发现网上的大部分题解都是直接转发,更有意思了. 题目是派大星的烦恼,给了我们一张粉红图片,放进010editor里面 ...
 - CTFHub Web题学习笔记(Web前置技能+信息泄露题解writeup)
			
今天CTFHub正式上线了,https://www.ctfhub.com/#/index,之前有看到这个平台,不过没在上面做题,技能树还是很新颖的,不足的是有的方向的题目还没有题目,CTF比赛时间显示 ...
 - 五、Zookeeper基于API操作Node节点
			
安装zookeeper :linux下安装Zookeeper 3.4.14 zookeeper 分为5个包: org.apache.zookeeper //客户端主要类文件 org.apache.zo ...
 - STL——容器(List)list 的赋值操作
			
list.assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身 1 #include <iostream> 2 #include <list> ...
 - C++异常之五 异常和继承
			
异常和继承 异常也是类,我们可以创建自己的异常类,在异常中可以使用(虚函数,派生,引用传递和数据成员等), 下面用一个自制的数组容器Vector,在对Vector初始化时来对Vector的元素个数进行 ...
 - 刚入坑之C#《方法》解说
			
说好的用一周时间学方法,我都快耽误成两周了.原因就是跟着传智播客的课程做了个飞行棋项目,想要梳理其中的方法却把自己绕晕了.那接下来我先说一下我学到方法的内容,在最后献上飞行器项目的代码,当然是传智播客 ...
 - 多任务-python实现-进程pool(2.1.9)
			
@ 目录 1. 概念 2.python代码实现 1. 概念 当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动 ...
 - Redis缓存穿透和缓存雪崩的面试题解析
			
前段时间去摩拜面试,然后,做笔试的时候,遇到了几道Redis面试题目,今天来做个总结.捋一下思路,顺便温习一下之前的知识,如果对您有帮助,左上角点下关注 ! 谢谢 文章目录 缓存穿透 缓存雪崩 大家都 ...
 - 浅析Linux 64位系统虚拟地址和物理地址的映射及验证方法
			
虚拟内存 先简单介绍一下操作系统中为什么会有虚拟地址和物理地址的区别.因为Linux中有进程的概念,那么每个进程都有自己的独立的地址空间. 现在的操作系统都是64bit的,也就是说如果在用户态的进程中 ...