垃圾收集器(对象回收条件,四大引用,对象的自我拯救)


概述
  • 前面我l们了解到了Java内存运行时区域的各个部分,其中程序计数器,虚拟机栈,本地方法栈这三个区域随线程而生,随线程而灭。因此这几个区域的内存分配和回收都具有确定性,因为方法结束或者线程结束时,内存就自然跟着回收了,所以这几个区域不需要过多的考虑回收的问题。
  • 而堆和方法区则不太一样,一个接口中的多个实现类需要的内存不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾回收器所关注的就是这部分的内存。

1.判断对象是否回收

(1)引用计数算法

  • 基本思想

给对象添加一个引用计数器,每当有一个地方引用它时,技术器加1,当引用失效时,计数器减1,任何时刻计数器为0的对象就是不可能再被使用的,这个对象就是需要被回收的。

  • 优缺点

引用计数算法的实现简单,判定效率也很高,大部分情况在它都是一个不错的算法。
但是一些主流的Java虚拟机中却没有使用这种算法,主要是因为它无法解决对象之间循环相互引用的问题。

package com.westmo.demo1;public class MyDemo1 {public Object instance=null;public static void main(String[] args) {test();}public static void test() {MyDemo1 myDemo1 = new MyDemo1();MyDemo1 myDemo2 = new MyDemo1();myDemo1.instance=myDemo2;myDemo2.instance=myDemo1;myDemo1=null;myDemo2=null;}
}
/上面的代码中,test()方法中,由程序的最后可以看出这两个对象已没有引用,应该被GC收集器回收,但是这两个对象又互相引用着对方,
所以他们的引用计数都不为0,引用计数算法就不行,后面的这种算法就不会存在这样的问题。

(2)可达性算法

(1)基本思想

这个算法的思想就是通过一系列“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则该对象就是不可达的,这个对象就会被判定为可回收对象,所走过的路径称为引用链。简而言之,就是以一个对象为起点,看能走到那个对象,走不到的对象就是不可达的。所以,这个起点就很重要。

如上图中,以GC Roots对象为起点,根本就无法走到Object5,Object6,Object7这三个对象,所以这三个对象就会被判定为可回收的对象。

(2)可作为GC Roots的对象
- 虚拟机栈中引用的对象(栈帧中的本地变量表)
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中引用的对象

2.引用

  • 概述

通过前面的学习我们知道,无论是通过引用计数算法设置计数器判断对象的引用还是通过可达性算法判断对象的引用链是否可达,都涉及到了引用这个问题。简而言之,如果一个变量是一个类类型,那么这个变量就是一个引用。这种定义很纯粹,这样的话,一个对象就只有被引用和没被引用两种状态。我们希望能描述这样一种对象,当内存空间足够时,则白柳这些对象,当内存空间不够时,则抛弃这些对象,通过这些引用的名字大概就能知道它们代表的意思。

(1)强引用

在程序代码中普遍存在,只要强引用存在,那么垃圾收集器就永远不会回收被引用的对象

(2)软引用
  • 当一个对象与GC Roots之间存在软引用时,垃圾收集器是否回收这个对象就去决与内存的紧张程度了,如果内存空间足够,不会被回收,如果内存空间不足时,将会难逃被回收的厄运。
  • 对象与GC Roots之间存在软引用时,这个对象被称为软可达对象。
  • 在垃圾收集器还没有回收它的时候,软引用对象就像强引用对象一样,都能被程序正常使用和访问,但需要通过软引用对象间接访问(通过SoftenReference类来实现)。
  • 用来描述有用但非必须的对象,只有在内存不足时JVM才会回收该对象,这一特性可以用来解决OOM问题(内存溢出),之一特性还可以用来实现图片缓存,网页缓存。
(3)弱引用
  • 这种引用指向的对象,一旦被垃圾收集器扫描到,就会被回收。
  • 通过WeakReference类来实现弱引用
  • 如果一个对象仅仅是偶尔使用,并且在使用时随时就能获取,但不影响此对象的垃圾收集,那么应该用WeakReference来引用该对象。
(4)虚引用
  • 虚引用是用PhantomReference创建的引用,它是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用来获得一个实例对象。
  • 虚引用的唯一作用: 一个对象设置虚引用就是在这个对象在被垃圾收集器回收时收到一个系统通知。可以利用虚引用来做一些对象销毁前的操作,如资源释放等。

3.对象的自我拯救(生存还是死亡)

(1)概述

前面我们学了可达性算法,那一个对象在可达性算法中已经是不可达对象,那么这个对象就真正非死不可吗?其实要宣告一个对象的死亡,没有这么简单,至少要经过两次标记过程,不可达的对象只是出于“缓刑”阶段。

(2)自我拯救

如果一个对象在通过可达性算法分析后,发现没有与GC Roots相连接的引用链,那么它将会被第一次标记并进行第一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。

  • 当对象没有重写finalize()方法或者finalze()方法已经被虚拟机调用过,虚拟机讲这两种情况都认为此对象没有必要执行finalize()方法,即自救失败。
  • 当对象重写了finalize()方法时,那么这个对象将会被放置在一个叫做F-Queue的队列之中,后面垃圾收集器将会对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己,只要与引用链上的任何一个对象建立关联即可),如把当前对象的引用this赋值给某对象的类变量/成员变量即可。第二次标记时这个对象讲将会被移除“缓刑”阶段(自救成功),如果没有与引用链上的对象建立关联,那就自救失败。

深入理解Java虚拟机(三)——对象已死吗相关推荐

  1. 深入理解java虚拟机 (三) 第二版

    参考资料 本书名为"深人理解Java虚拟机",但要想深人理解虚拟机,仅凭- -本书肯定是远远不够的,读者可以通过以下信息找到更多关于Java虚拟机方面的资料.我在写作此书的时候,也 ...

  2. 深入理解java虚拟机(三)GC垃圾回收-对象存活算法

    文章目录 前言 一.引用计数算法 二.可达性分析算法 三.了解引用 结尾 前言 在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还&qu ...

  3. java占位符填充_程序员:深入理解Java虚拟机,对象的内存布局

    在 HotSpot 虚拟机中,对象在内存中存储的布局分为 3 块区域:对象头 ( Header ) .实例数据 ( InstanceData ) 和对齐填充 (Padding) . 一.对象的内存布局 ...

  4. java中对象的生存期_深入理解Java虚拟机-判断对象是否存活算法与对象引用

    我们知道Java中的对象一般存放在堆中,但是总不能让这些对象一直占着内存空间,这些对象最终都会被回收并释放内存,那么我们如何判断对象已经成为垃圾呢?这篇文章会提出两种算法解决这个问题.另外,本文还要谈 ...

  5. 【深入Java虚拟机JVM 07】JVM如何判断对象已死

    说明:文章所有内容均摘自<深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)> 在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些 ...

  6. java判断对象已经被回收_Java中JVM判断对象已死的基本算法分析

    原标题:Java中JVM判断对象已死的基本算法分析 jvm中 有各种的垃圾收集器,每个收集器都有各自的算法. 但是一切的根本都需要找到找到应该被消除的对象,理解如何找到死亡对象才是理解垃圾收集器的基础 ...

  7. 深入理解java虚拟机第一第二部分(周志明第三版)

    文章目录 深入理解java虚拟机(周志明第三版) 第一部分.Java的前世今生和未来展望 1.1.概述 1.2.java技术体系 1.3.Java发展史(只记录比较重要的) 1.4.Java虚拟机家族 ...

  8. 《深入理解java虚拟机》笔记1——Java内存区域与Java对象

    运行时数据区域 JVM载执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程 ...

  9. 深入理解Java虚拟机(第三弹)- JVM 内存分配与回收策略原理,从此告别 JVM 内存分配文盲

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:打卡活动第二期来啦,100% 能获得奖品个人原创+1博客:点击前往,查看更多 虚拟机系列文章 深入理解 Java ...

  10. 《深入理解java虚拟机》学习笔记--第三章:垃圾收集器与内存分配策略

    GC所关心的问题就是: (1)那些内存需要回收? (2)何时回收? (3)怎么回收? 关注点:在程序计数器.java虚拟机栈.本地方法栈中,这些内存都是随着线程的创建而创建,销毁而销毁,这部分是不需要 ...

最新文章

  1. nginx mac 服务器 html,Mac上搭建 nginx 服务器
  2. IllegalArgumentException:argument type mismatch
  3. 有趣的应用 | 使用RNN预测股票价格系列一
  4. 快速构建Windows 8风格应用5-ListView数据控件
  5. python 并查集_python 实现并查集源代码 | 学步园
  6. 【[TJOI2014]上升子序列】
  7. 【路径规划】基于matlab模拟退火算法求解多车型路径规划问题【含Matlab源码 913期】
  8. 城市轨道交通运营票务管理论文_城市轨道交通运营管理浅析
  9. diabetes影响因子2017_DIABETES
  10. 适用于 Linux 系统的 11 款图像查看器
  11. excel npoi 连接_MVC导出Excel之NPOI简单使用(一)
  12. please insert the disc labeled ‘Ubuntu 18.04.5 LTS _Bionic Beaver_ - Release amd64 (20200806.1)‘ in
  13. 网络小说写作套路_关于网络写作的6个常见问题,已回答
  14. 苹果Mac合上屏幕怎样才能不休眠?
  15. 如何redis关闭保护模式,取消密码登录
  16. 【项目1】家庭记账软件
  17. linux串口文件传输助手怎么用,SerialTool: SerialTool是一个实用的串口调试工具,这款工具支持串口调试助手、波形显示和文件传输等功能...
  18. Java去掉标点符号的方法
  19. STM32F103C8T6+无FIFO的OV7670的输出测试图像实例代码
  20. html中的空格怎么写,html中空格代码是什么?(总结)

热门文章

  1. 你知道什么是通配符证书吗?
  2. 【Python】phonenumbers
  3. 奥比中光Orbbec Astra-Mini RGB-D 3D体感摄像头在ROS(indigo)使用简介
  4. 【拓展】深度解析蚂蚁Ant Design的设计原则
  5. 思考的技术- 读书笔记
  6. 用PHP校验EMAIL地址的正确方法
  7. python easyicon同类型ico图片批量爬取
  8. UctoX for Mac v2.8.8 发票管理软件
  9. 别再说不了解非接触液位传感器了?只需三分钟就能搞懂
  10. Source Insight 4.0打开一会就闪退 解决方法