一.GC如何判断一个对象为”垃圾”的
java堆内存中存放着几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”。那么GC具体通过什么手段来判断一个对象已经”死去”的?

1.引用计数算法(已被淘汰的算法)
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

目前主流的java虚拟机都摒弃掉了这种算法,最主要的原因是它很难解决对象
之间相互循环引用的问题。尽管该算法执行效率很高。

2.可达性分析算法
目前主流的编程语言(java,C#等)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如下图所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。

在Java语言中,可作为GC Roots的对象包括下面几种:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  • 方法区中类静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象。

二.被GC判断为”垃圾”的对象一定会回收吗
即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。(即意味着直接回收)

如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。

finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了。

代码示例:

public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null; public void isAlive() {
System.out.println("yes,i am still alive:)");
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize mehtod executed!");
FinalizeEscapeGC.SAVE_HOOK = this;
} public static void main(String[] args) throws Throwable {
SAVE_HOOK = new FinalizeEscapeGC();
// 对象第一次成功拯救自己
SAVE_HOOK = null;
System.gc();
// 因为finalize方法优先级很低,所以暂停0.5秒以等待它
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no,i am dead:(");
}
// 下面这段代码与上面的完全相同,但是这次自救却失败了
SAVE_HOOK = null;
System.gc();
// 因为finalize方法优先级很低,所以暂停0.5秒以等待它
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no,i am dead:(");
}
}
}

  

运行结果:

finalize mehtod executed!
yes,i am still alive:)
no,i am dead:(

SAVE_HOOK对象的finalize()方法确实被GC收集器触发过,并且在被收集前成功逃脱了。另外一个值得注意的地方是,代码中有两段完全一样的代码片段,执行结果却是一次逃脱成功,一次失败,这是因为任何一个对象的finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法不会被再次执行,因此第二段代码的自救行动失败了。因为finalize()方法已经被虚拟机调用过,虚拟机都视为“没有必要执行”。(即意味着直接回收)

GC是如何判断一个对象为"垃圾"的?被GC判断为"垃圾"的对象一定会被回收吗?的更多相关文章

  1. javascript-如何判断一个对象为数组

    Q:如何判断一个对象是否为数组? A1:判断对象的constructor是否指向Array, 接着判断对应的特殊属性,如length,splice之类.这个很容易冒充. A2:使用instanceof ...

  2. 用JavaScript判断一个对象是否数组?

    Q:如何判断一个对象是否为数组? A1:判断对象的constructor是否指向Array, 接着判断对应的特殊属性,如length,splice之类.这个很容易冒充. A2:使用instanceof ...

  3. GC Roots的理解以及如何判断一个对象为“垃圾”

    http://blog.csdn.net/Great_Smile/article/details/49935307 这篇博客中讲解了哪些可以作为GC Roots以及如何判断一个对象为垃圾

  4. java面试一日一题:如何判断一个对象是否为垃圾对象

    问题:请讲下在java中如何判断一个对象是否为垃圾 分析:该问题主要考察对java中的垃圾回收,用什么方式去识别一个对象是垃圾: 回答要点: 主要从以下几点去考虑, 1.GC回收的是什么,回收发生在内 ...

  5. 垃圾回收机制GC知识再总结兼谈如何用好GC

    一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...

  6. 垃圾回收机制GC知识再总结兼谈如何用好GC(转)

    作者:Jeff Wong 出处:http://jeffwongishandsome.cnblogs.com/ 本文版权归作者和博客园共有,欢迎围观转载.转载时请您务必在文章明显位置给出原文链接,谢谢您 ...

  7. 垃圾回收机制GC知识再总结兼谈如何用好GC(其他信息: 内存不足)

    来源 图像操作,易内存泄露,边界像素 一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对 ...

  8. win10 uwp 如何判断一个对象被移除

    原文:win10 uwp 如何判断一个对象被移除 有时候需要知道某个元素是否已经被移除,在优化内存的时候,有时候无法判断一个元素是否在某个地方被引用,就需要判断对象设置空时是否被回收. 本文告诉大家一 ...

  9. 2018-8-10-win10-uwp-如何判断一个对象被移除

    title author date CreateTime categories win10 uwp 如何判断一个对象被移除 lindexi 2018-08-10 19:16:50 +0800 2018 ...

随机推荐

  1. python pycharm错误集锦

    url:http://www.cnblogs.com/hinimix/p/8016859.html 1, this list creation could be rewritten as a list ...

  2. 通过OpenSSL来生成PEM格式的私钥、PKCS8格式的私钥、公钥|pfx格式的私钥、cer格式的公钥

    1.生成PEM格式RSA私钥 不对输出的文件内容进行加密 openssl genrsa -out private-rsa.key 对输出的文件内容进行加密(DES/AES128/AES256等) op ...

  3. 利用art.template模仿VUE 一次渲染多个模版

    TypeScript代码 import template = require('art-template/lib/template-web'); interface TemplateBindConfi ...

  4. opencv yuvNV21转RGB

    void yuv420Torgb() { FILE *fp = fopen("D:\\1.yuv","rb"); ; ; uchar *yuvdata = / ...

  5. ASP程序加密/解密方法大揭密

      如今,用ASP技术构建的网站随处可见.由于ASP脚本是在服务器上解释执行的(无法编译),因此你辛苦开发出来的ASP代码,很容易被人拷去任意修改,如何保护ASP源代码呢?这是每个ASP站长都会遇到的 ...

  6. Qt 图片缩放参数计算

    缩放图片 void VCImgWidget::wheelEvent(QWheelEvent *event) { ) { // 当滚轮远离使用者时 //ui->textEdit->zoomI ...

  7. Lyrics of the song 99 Bottles of Beer

    99 bottles of beer on the wall, 99 bottles of beer.Take one down and pass it around, 98 bottles of b ...

  8. SpringBoot系列教程JPA之query使用姿势详解之基础篇

    前面的几篇文章分别介绍了CURD中的增删改,接下来进入最最常见的查询篇,看一下使用jpa进行db的记录查询时,可以怎么玩 本篇将介绍一些基础的查询使用姿势,主要包括根据字段查询,and/or/in/l ...

  9. bat启动OpenOffice4

    start "" /d "C:\Program Files (x86)\OpenOffice 4\program" "soffice.exe" ...

  10. 多生产者多消费者(第二种方式2.1)基于BlockingQueue

    public class Producer implements Runnable { //静态变量只初始化一次 private static AtomicInteger count = new At ...