java gc回收算法_Java GC回收算法-判定一个对象是否可以回收

开源推荐

推荐一款一站式性能监控工具(开源项目)

Pepper-Metrics是跟一位同事一起开发的开源组件,主要功能是通过比较轻量的方式与常用开源组件(jedis/mybatis/motan/dubbo/servlet)集成,收集并计算metrics,并支持输出到日志及转换成多种时序数据库兼容数据格式,配套的grafana dashboard友好的进行展示。项目当中原理文档齐全,且全部基于SPI设计的可扩展式架构,方便的开发新插件。另有一个基于docker-compose的独立demo项目可以快速启动一套demo示例查看效果https://github.com/zrbcool/pepper-metrics-demo。如果大家觉得有用的话,麻烦给个star,也欢迎大家参与开发,谢谢:)

进入正题...

GC的出现解放了程序员需要手动回收内存的苦恼,但我们也是要了解GC的,知己知彼,百战不殆嘛。

常见的GC回收算法主要包括引用计数算法、可达性分析法、标记清除算法、复制算法、标记压缩算法、分代算法以及分区算法。

其中,引用计数法和可达性分析法用于判定一个对象是否可以回收,其他的算法为具体执行GC时的算法。

今天来聊聊可达性分析法,并说明一下什么样的对象才是真正可以被回收的。

在介绍引用计数法的时候,我们提到了此种算法的循环引用的缺陷,所以Java没有使用此种算法。

那Java使用的是啥算法来标记一个对象是否是垃圾对象呢?

Java是通过判断一个对象是否可触及,以及一个对象的引用类型(强引用、软引用、弱引用、虚引用)来决定是否回收这个对象。

本文将根据上述,分为两部分进行介绍。

最后会简单介绍一下GC回收过程中保证数据一致性的方法:Stop the World

1 如何判断一个对象是否可触及?

判断是否可触及包含两个要素: 通过可达性分析该对象到GC Root不可达,如果不可达会进行第一次标记。 已经丧失"自救"机会,如果没有自救机会,会进行第二次标记,此时该对象可回收。

1.1 可达性分析

可达性分析法定义了一系列称为"GC Roots"的对象作为起始点,从这个起点开始向下搜索,每一条可达路径称为引用链,当一个对象没有任意一条引用链可以到达"GC Roots"时,那么就对这个对象进行第一次"可回收"标记。

那么什么是GC Root呢?

可以理解为由堆外指向堆内的引用。

那么都有哪些对象可以作为GC Roots呢? 包括如下几种 代码中某一方法中的局部变量 类变量(静态变量) 常量 本地方法栈中引用的对象 * 已启动且未停止的线程

下面以一段代码来简单说明一下前三类

class Test {

private static A a = new A(); // 静态变量 public static final String CONTANT = "I am a string"; // 常量

public static void main(String[] args) {

A innerA = new A(); // 局部变量 }

}

class A {

...

}

这段代码的运行时内存图示如下:

首先,类加载器加载Test类,会初始化静态变量a,将常量引用指向常量池中的字符串,完成Test类的加载;

然后,main方法执行,main方法会入虚拟机方法栈,执行main方法会在堆中创建A的对象,并赋值给局部变量innerA。

此时GC Roots状态如下:

当main方法执行完出栈后,变为:

第三个对象已经没有引用链可达GC Root,此时,第三个对象被第一次标记。

1.2 对象的"自救"

一个被可达性分析标记为可回收的对象,是有机会进行自救的。前提是:覆写了Object的finalize()方法,且GC还没有执行该对象的finalize()方法。

先来看一下finalize方法的定义

/*** Called by the garbage collector on an object when garbage collection* determines that there are no more references to the object.* A subclass overrides the {@code finalize} method to dispose of* system resources or to perform other cleanup.*

* The general contract of {@code finalize} is that it is invoked* if and when the Java™ virtual* machine has determined that there is no longer any* means by which this object can be accessed by any thread that has* not yet died, except as a result of an action taken by the* finalization of some other object or class which is ready to be* finalized. The {@code finalize} method may take any action, including* making this object available again to other threads; the usual purpose* of {@code finalize}, however, is to perform cleanup actions before* the object is irrevocably discarded. For example, the finalize method* for an object that represents an input/output connection might perform* explicit I/O transactions to break the connection before the object is* permanently discarded.*

* The {@code finalize} method of class {@code Object} performs no* special action; it simply returns normally. Subclasses of* {@code Object} may override this definition.*

* The Java programming language does not guarantee which thread will* invoke the {@code finalize} method for any given object. It is* guaranteed, however, that the thread that invokes finalize will not* be holding any user-visible synchronization locks when finalize is* invoked. If an uncaught exception is thrown by the finalize method,* the exception is ignored and finalization of that object terminates.*

* After the {@code finalize} method has been invoked for an object, no* further action is taken until the Java virtual machine has again* determined that there is no longer any means by which this object can* be accessed by any thread that has not yet died, including possible* actions by other objects or classes which are ready to be finalized,* at which point the object may be discarded.*

* The {@code finalize} method is never invoked more than once by a Java* virtual machine for any given object.*

* Any exception thrown by the {@code finalize} method causes* the finalization of this object to be halted, but is otherwise* ignored.** @throws Throwable the {@code Exception} raised by this method* @see java.lang.ref.WeakReference* @see java.lang.ref.PhantomReference* @jls 12.6 Finalization of Class Instances*/

protected void finalize() throws Throwable { }

大致翻译一下前两段:当GC判定某一对象不再通过任一形式被引用时,GC会调用该对象的finalize方法。方法执行时,可以进行任何操作,包括将这个对象再次赋值给某一变量引用,但其主要目的还是做一些对象的清除操作。

其实在finalize方法中,只要将这个对象的引用(this)再次赋值给某一变量,这个对象就可以"自救"。

如果一个对象在finalize阶段也没有完成自救,那么就真的要被回收了。

下面演示一个"自救"的例子:

public class SaveMe {

public static SaveMe saveMe;

public static void main(String[] args) throws InterruptedException {

saveMe = new SaveMe();

saveMe = null; // 取消引用,经过可达性分析,上面new出来的对象不再可达GC Root System.gc(); // 第一次GC,会执行finalize方法 Thread.sleep(1000);

if (saveMe == null) {

System.out.println("对象为null");

} else {

System.out.println("对象不为null");

}

// 经过上面的过程,对象已经自救了,这里再次将其引用置空 saveMe = null;

System.gc(); // 不会再执行finalize方法,没有机会自救了 Thread.sleep(1000);

if (saveMe == null) {

System.out.println("对象为null");

} else {

System.out.println("对象不为null");

}

}

// finalize方法全局只会执行一次 @Override

protected void finalize() throws Throwable {

super.finalize();

saveMe = this; // 进行自救 }

}

上述代码很简明,可根据注释理解。代码执行结果如下:

2 不同引用类型的回收

Java中有四种引用类型,引用强度由强到弱:强引用、软引用、弱引用、虚引用。针对不同的引用类型,GC的回收策略不同。

2.1 强引用

通过关键字new的对象就是强引用对象,强引用指向的对象任何时候都不会被回收,宁愿OOM也不会回收。

2.2 软引用

如果一个对象持有软引用,那么当JVM堆空间不足时,会被回收。

一个类的软引用可以通过java.lang.ref.SoftReference持有。

2.3 弱引用

如果一个对象持有弱引用,那么在GC时,只要发现弱引用对象,就会被回收。

一个类的弱引用可以通过java.lang.ref.WeakReference持有。

2.4 虚引用

几乎和没有一样,随时可以被回收。

通过PhantomReference持有。

3 Stop the World

问题的出现:如果程序一边执行,一边进行可达性分析的标记操作,那么有可能刚标记完一个对象,这个对象又再次被赋值给其他的引用。这样就有可能回收掉正在使用的对象。

解决这个问题的方式就是Stop the World(STW),STW会在所有线程到达一个安全点时,暂停掉所有应用线程的执行,然后开始专心的标记垃圾对象。这样就保证了数据的一致性,不会导致误回收。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/431877.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动态规划求一个序列的最长回文子序列(Longest Palindromic Substring )

1、问题描述 给定一个字符串(序列),求该序列的最长的回文子序列。 2、分析 需要理解的几个概念: ---回文 ---子序列 ---子串 http://www.cnblogs.com/LCCRNblog/p/4321398.html这一篇文章描述了利用动态规划求解两个序列的最长公共…

java类作用域标识符_java入门 (二) 标识符、数据类型、类型转换、变量、常量、作用域...

java入门(二)标识符数据类型类型转换变量、常量、作用域本次笔记引用B站:狂神说,虽然早就会了,现在回头来敲下基础,加深印象1.标识符:java所有的组成部分都需要名字。类名丶变量名丶方法名统称为标识符。标识符大小写敏感。不能使…

0421 AutoLayout的实践/基本使用

历史:从iOS 6开始 ,之前都是3.5英寸没有考虑到适配.iPhone5 变成了4英寸,所以推出了Auto Layout理解: 另外一个体系,去描述位置.像素:点: // 勘误: 图中的像素应为 “点"// 写上以上代码,就可以删掉系统创建的控制器和storyBoard了.// 创建控制器,勾选Xib[]拖一个uiview背…

C#实现UTC时间与Datetime转换

为了便于传输,通信过程中传输的都是:当前时间跟标准时间相隔的秒数,并且是以16进制字节的形式传输的。 1 public double ConvertDateTimeInt(System.DateTime time)//将时间格式的数据类型转换成浮点数类型 2 {3 doubl…

java selenium iframe_java selenium处理Iframe中的元素示例

java selenium 处理Iframe 中的元素有时候我们定位元素的时候,发现怎么都定位不了。 这时候你需要查一查你要定位的元素是否在iframe里面阅读目录什么是iframeiframe 就是HTML 中,用于网页嵌套网页的。 一个网页可以嵌套到另一个网页中,可以…

des 向量 java_在JAVA中使用DES算法

DES算法提供CBC, OFB, CFB, ECB四种模式,MAC是基于ECB实现的。一、数据补位DES数据加解密就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,按照需求补足8个字节(通常补00或者FF,根…

可访问性不一致的原因与解决方法

出现原因,其中一个是返回参数的访问级别小于函数的访问级别,也就是说当定义一个返回参数的方法的时候,如果返回参数的访问级别低于方法的访问级别,此时就会出现这样的错误。如果返回的参数不能被访问,那么定义的返回的方法也是错误…

jQuery 事件 - bind() 方法

定义和用法 bind() 方法为被选元素添加一个或多个事件处理程序&#xff0c;并规定事件发生时运行的函数。 实例1&#xff08;一个事件&#xff09; 记得把js引用地址换掉 当点击鼠标时&#xff0c;隐藏或显示 p 元素&#xff1a; <html><head><script type"…

java 圆形按钮,如何在Java中创建圆形的JButton?

I want to create rounded JButton in Java...For that I use rounded image and placed that image on button but I didnt get rounded button..please any one can tell how to create rounded button in Java like show in below figure..thanks in advance.....解决方案If…

Python学习 Day 3 字符串 编码 list tuple 循环 dict set

字符串和编码 字符 ASCII Unicode UTF-8 A 1000001 00000000 01000001 1000001 中 x 01001110 00101101 11100100 10111000 10101101 格式化 在Python中&#xff0c;采用的格式化方式和C语言是一致的&#xff0c;用%实现&#xff0c;举例如下&#xff1a; >>&…

java hibernate dto_java – 正确使用Entity和DTO在Restful Web服务中...

有很多文章指出使用JPA / hibernate不需要使用DTO同样在article由SO成员Bohzo我很少需要阅读DTO甚至在articles中反对暴露实体声明当实体没有任何行为时(当它们是POJO时)不需要具有DTO,如在贫血域模型中那样假设有一个Entity类class Department{List employees //lazily loaded…

构建之法现代软件概述

软件工程&#xff1a;就是用科学的知识工程和技术原理来定义&#xff0c;开发&#xff0c;维护软件的一门学科。软件工程的目标&#xff1a;付出较低开发成本&#xff1b;达到要求的功能&#xff1b;取得较好的性能&#xff1b;开发的软件易于移植&#xff1b;只需较低的维护费…

java 高飞_高飞(土木与水利工程学院)老师 - 合肥工业大学

高飞高飞老师的简历姓名:高飞 性别:男 出生年月:1962.11最终学位:硕士 毕业院校:合肥工业大学职称:教授 职务:副院长电话:0551-2901441,13705510744E-mail:gaofeihfut.edu.cn现从事专业:测绘科学与技术社会团体任职:1.全国高等学校测绘学科教学指导委员会,委员;2.中国测绘学会工…

Python_03-数据类型

1.1 数据类型 基本数据类型&#xff1a;字符串&#xff0c;整数&#xff0c;浮点数&#xff0c;布尔型 集合类型&#xff1a;列表&#xff08;list), 元组&#xff08;tuple), 字典&#xff08;dictionary或hash) 列表&#xff08;list&#xff09;的定义&#xff1a; aList …

java串口监听超时_从串口读取时如何实现read()的超时(C / C)

有几种可能的方法 . 如果程序最终将定时多个i / o操作&#xff0c; select() 是明智的选择 .但是&#xff0c;如果唯一的输入来自此i / o&#xff0c;则选择非阻塞i / o和时序是一种简单的方法 . 我已经将它从单字符i / o扩展到多字符&#xff0c;使其成为一个更普遍的完整示例…

64位操作系统下IIS报“试图加载格式不正确的程序”错误

缘由&#xff1a;在64位操作系统下IIS发布32位的项目&#xff0c;报“项目依赖的dll无法读取&#xff0c;试图加载格式不正确的程序”错误。 原因&#xff1a;程序集之间的通讯要么全是64位环境下的&#xff0c;要么全是32位环境下的。不能混编访问。不然会出现“试图加载格式不…

java训练_Java练习

package exec;/*2.根据圆柱体的半径和高&#xff0c;使用下面的公式&#xff0c;计算圆柱的体积面积半径*半径*π体积面积*高 */public class work01 {public static void main(String[] args) {// TODO Auto-generated method stub//定义圆柱的高和半径&#xff0c;面积&#…

jwPlayer为js预留的回调方法

参考地址&#xff1a;http://www.cnblogs.com/lori/archive/2014/05/05/3709459.html 应用场合 播放时记录当前视频的时间&#xff0c;播放完成时写入完成的时间&#xff0c;像这些功能&#xff0c;我们都可以通过事件回调的方法解决&#xff0c;即为events属性赋相应的值&…

新手学java7编程_新手学Java 7编程:面向对象程序设计

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼面向对象程序设计Java的核心是面向对象程序设计(OOP)。面向对象方法论与Java是密不可分的&#xff0c;而Java所有的程序至少在某种程度上都是面向对象的。因为OOP对Java的重要性&#xff0c;所以在开始编写一个哪怕是很简单的Java程…

脚本两则--用于快速部署HADOOP,SPARK这些(特别是VM虚拟机模板部署出来的)。。...

感觉可能只是适合我自己的部署习惯吧&#xff0c;且只针对CENTOS6及以下版本&#xff0c;以后有时间&#xff0c;可能还是要改进。。 1&#xff0c;从VM的模块产生的虚拟机&#xff0c;如何快速搞定网络配置&#xff1f; #!/bin/bash#usage:./init_cdh_sys.sh hostname hostip …