文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习
一、对象的标记
1、什么是标记?怎么标记?
第一个问题相信大家都知道,标记就是对一些已死的对象打上记号,方便垃圾收集器的清理。 至于怎么标记,一般有两种方法:引用计数和可达性分析。
引用计数实现起来比较简单,就是给对象添加一个引用计数器,每当有一个地方引用它时就加1,引用失效时就减1,当计数器为0的时候就标记为可回收。这种判断效率很高,但是很多主流的虚拟机并没有采用这种方法,主要是因为它很难解决几个对象之间循环引用的问题,虽然不怎么用了,但还是值得我们学习!
public class Test { private Object obj; Public static void main(){ Test t1=new Test(); Test t2=new Test(); t1.obj=t2; t2.obj=t1; t1=null; t2=null; //如果对象在这行发生gc,那么t1和t2对象是否能被回收 System.gc(); } }
可达性分析的基本思路就是:通过将一些称为"GC Roots"的对象作为起始点,从这些节点开始搜索,搜索和该节点发生直接或者间接引用关系的对象,将这些对象以链的形式组合起来,形成一张“关系网”,又叫做引用链。最后垃圾收集器就回收一些不在这张关系网上的对象。如图:
连接GC Roots对象的object是确定还存活的对象,而右边的die obj由于和GCROOTS没有关系,所以会标记为可回收的对象。目前主流的商用虚拟机用的都是类似的方法。那什么对象才能作为“GC Roots”呢?在java中,有四种对象可以作为“GC Roots”
1:栈帧(第一章的名词)中的引用对象。(栈中的)
2:静态属性引用的对象。(方法区中的)
3:常量引用的对象。(方法区中的)
4:本地方法栈中JNI引用的对象。(本地方法栈中的)
二、对象的二次回收
说过对象的标记,但是不是被标记了就肯定会被回收呢?不知道小伙伴们记不记得Object类有一个finalize()方法,所有类都继承了Object类,因此也默认实现了这个方法。
finalize的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存.所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作.
finalize()在什么时候被调用?
有三种情况
1.所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候.
2.程序退出时为每个对象调用一次finalize方法。
3.显式的调用finalize方法
这个方法的用途就是:在该对象被回收之前,该对象的finalize()方法会被调用。这里的回收之前指的就是被标记之后,问题就出在这里,有没有一种情况就是原本一个对象开始不再上一章所讲的“关系网”(引用链)中,但是当开发者重写了finalize()后,并且将该对象重新加入到了“关系网”中,也就是说该对象对我们还有用,不应该被回收,但是已经被标记啦,怎么办呢?
针对这个问题,虚拟机的做法是进行两次标记,即第一次标记不在“关系网”中的对象。第二次的话就要先判断该对象有没有实现finalize()方法了,如果没有实现就直接判断该对象可回收;如果实现了就会先放在一个队列中,并由虚拟机建立的一个低优先级的线程去执行它,随后就会进行第二次的小规模标记,在这次被标记的对象就会真正的被回收了。
总结:简单说,对象先进行第一次标记,在下一次GC之前会执行对象的finalize()方法。在执行finalize()方法的时候判断对象是否实现了finalize()方法,没有实现直接清除;实现了,将对象放在一个队列中执行finalize方法,进行第二次标记
在java根搜索算法中判断对象的可达性,对于不可达的对象,也并不一定是必须清理。这个时候有一个缓刑期,真正的判断一个对象死亡,至少要经过俩次标记过程:如果对象在进行根搜索后发现没有与GC roots相关联的引用链,那他将会第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这俩种情况都视为“没有必要执行”。
即当一个对象重写了finalize()方法的时候,这个对象被判定为有必要执行finalize()方法,那么这个对象被放置在F-Queue队列之中,并在稍后由一条由虚拟机自动建立的、低优先级的Finalizer线程去执行。这里所谓的执行是指虚拟机会出发这个方法,但不承诺会等待它运行结束。这样做的原因:如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(极端的情况下),将可能会导致F-Queue队列中的其他对象永久处于等待状态,甚至导致整个内存回收系统崩溃。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己----只要重新与引用链上的任何建立关联即可,那么在第二次标记时它将会被移出“即将回收”的集合;如果对象这时候没有逃脱,就会被回收。代码示例:参考《深入理解java虚拟机》对应章节
总结
以上就是本文关于浅谈Java回收对象的标记和对象的二次标记过程的全部内容,希望对大家学习Java有所帮助。感兴趣的朋友可以参阅:Java虚拟机装载和初始化一个class类代码解析 、Java编程思想对象的容纳实例详解、Java系统的高并发解决方法详解等,有什么问题可以随时留言,小编会及时回复大家的。
原文地址是:http://www.piaodoo.com/thread-13231-1-2.html 丝袜控www.txdah.com 131www.buzc.org学习之外可赏心悦目有助更好地学习!
浅谈Java回收对象的标记和对象的二次标记过程_java - JAVA的更多相关文章
-
转: 浅谈C/C++中的指针和数组(二)
转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html 浅谈C/C++中的指针和数组(二) 前面已经讨论了指针和数组 ...
-
反射入门-浅谈反射用途_根据Ado游标对象创建list集合
本人大二菜鸟一只,今天在上课期间有个同学看着C#反射的内容说反射没什么用,一时之间也想不到什么更好的例子,就写了个根据泛型类型和游标反射创建List集合的Demo. 首先创建一个用于封装对应数据的en ...
-
浅谈 JS 内存泄露方式与避免方法(二)
Concept WHAT : 内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束.正常情况下,垃圾回收器在DOM元素和event处理器不被引用或访问的时候回收它们.但是,IE的早些 ...
-
浅谈java垃圾回收机制
今天看thinking in java,里面很详细的谈到java垃圾回收器机制,看完后让我对这神秘的区域有一定的了解,特写一些小总结记录下来. 分两点来说. 第一点:Object.finalize() ...
-
浅谈Java中的对象和引用
浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...
-
浅谈java内存分配和回收策略
一.导论 java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家聊聊java对象的在内存中的分配.通俗的讲,对象的内存分配 ...
-
(转)Java回收对象的标记 和 对象的二次标记过程
Java回收对象的标记 和 对象的二次标记过程 二次标记 针对这个问题,虚拟机的做法是进行两次标记,即第一次标记不在“关系网”中的对象.第二次的话就要先判断该对象有没有实现finalize()方法了, ...
-
浅谈Java中的对象和对象引用
浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...
-
(转)浅谈Java中的对象和对象引用
原文地址: http://www.cnblogs.com/dolphin0520/p/3592498.html 在Java中,有一组名词经常一起出现,它们就是"对象和对象引用",很 ...
随机推荐
-
js⑦
立即执行函数or自执行函数 为了避免全局变量的产生.(function(){ //var a = 10; //var b = 20;//console.log(a,b); -------------v ...
-
网络电视精灵~分析~~~~~~简单工厂模式,继承和多态,解析XML文档,视频项目
小总结: 所用技术: 01.C/S架构,数据存储在XML文件中 02.简单工厂模式 03.继承和多态 04.解析XML文档技术 05.深入剖析内存中数据的走向 06.TreeView控件的使用 核心: ...
-
Javascript:getElementsByClassName
背景: 由于原生的getElementsByClassName不支持在指定标签中查找指定元素为指定class的情况,所以,这里舍弃了原生的方法调用 方法一: function getElement ...
-
python基础(五)列表,元组,集合
列表 在python中是由数个有序的元素组成的数据结构,每一个元素对应一个index索引来隐式标注元素在列表中的位置.是python中最常用的一种数据类型.需要注意的是列表中可以有重复相同的数据. 列 ...
-
Java进阶(十六)使用new Date()和System.currentTimeMillis()获取当前时间戳
java使用new Date()和System.currentTimeMillis()获取当前时间戳 在开发过程中,通常很多人都习惯使用new Date()来获取当前时间,使用起来也比较方便,同时还可 ...
-
vim配置文件(本人喜欢的风格)
在/etc/vimrc这个文件 if v:lang =~ "utf8$" || v:lang =~ "UTF-8$" set fileencodings=utf ...
-
利用git提交代码
一.首先需要下载git 查看电脑是否安装git,打开终端,输入git,回车如果输出如下,则代表已安装了git 如果未安装,则会输出: 按照提示输入:sudo apt-get install git即可 ...
-
Listary的使用
前几天研究米老师语录之后,开始对工具的使用着迷.现在的慢是为了以后的快,所以现在研究的一些东西,是为了以后在工作中可以更加快速的提高效率. 最近找到了一款很不错的软件,Listary.想给小伙伴们介绍 ...
-
保存一个经常用的Makefile
############################################################# # Generic Makefile for C/C++ Program # ...
-
Dubbo透传traceId/logid的一种思路
前言: 随着dubbo的开源, 以及成为apache*项目. dubbo越来越受到国内java developer欢迎, 甚至成为服务化自治的首选方案. 随着微服务的流行, 如何跟踪整个调用链, 成 ...