JVM理论:(二/2)判断对象是否已死

讲到垃圾回收,首先就要先知道哪些对象是可以回收的。

可达性算法

  这里有必要先了解一下可达性算法,以“GC Roots”的对象作为起始点,若从“GC Roots”到某对象不可达时,此对象会被判定为可回收对象。

  可作为GC Roots的对象包括下面几种:

  1、虚拟机栈(栈帧中的本地变量表)中引用的对象。

  2、方法区中类静态属性引用的对象。

  3、方法区中常量引用的对象。    ?有疑问

  4、本地方法栈中JNI(native方法)引用的对象。

  

  * 作为扩展知识了解一下引用计数法,给对象中添加一个引用计数器,当有一个地方引用它时,计数器值加1,当引用失效时,计数器值减1,计数器为0的对象表示可回收,这种算法存在一个问题,若两个都需要被回收的对象互相引用了,就会导致这两个本该被回收的对象无法被回收。

利用finalize()方法逃脱

  即使在可达性分析算法中不可达的对象,也并非马上非死不可,真正判定一个对象死亡至少要经历两次标记过程,判定过程如下:

  1、第一次标记

  如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它会被第一次标记,并根据是否有必要执行finalize()方法进行筛选,若对象没有覆盖finalize()方法或finalize()方法已经被虚拟机调用过,则表示没有必要执行finalize()方法,对象直接被回收。

  2、第二次标记

  如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个名为:F-Queue的队列之中,并在稍后由一条虚拟机自动建立的、低优先级的Finalizer线程去执行,但不保证一定会被执行或会等待它运行结束。

  finalize()方法是对象避免回收的最后一次机会,要成功拯救自己只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己(this)赋值给某个类变量或对象的成员变量。

  * 值得注意的是finalize()方法只能被系统自动调用一次,仅作为了解,一般不使用。

四种引用

  判断对象是否存活与“引用”有关,JDK1.2后,Java将引用分为强引用、软引用、弱引用、虚引用4种,引用强度一次减弱。

  将引用分类后,能满足这样的场景:当内存空间足够时,则保留在内存中,如果内存空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。  

  1、强引用:

  只要强引用存在,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠回收具有强引用的对象来解决内存不足的问题。

  在程序代码中普遍存在,创建代码即 Object a = new Object()。

  当在一个方法的内部有一个强引用,这个引用保存在栈中,而真正的引用内容(Object)保存在堆中。当这个方法运行完成后就会退出方法栈,则引用内容的引用不存在,这个Object会被回收。

  如果想中断强引用和某个对象之间的关联,a = null;,JVM会在合适的时间回收该对象。

  2、软引用:

  在系统将要发生内存溢出异常前,会把这些对象列进回收范围中准备进行第二次回收,如果这次回收还是没有足够的内存才会跑内存溢出异常。即在内存不足时JVM才会回收这些对象。

  软引用用来描述一些有用但并非必需的对象,可用于实现缓存:比如网页缓存、图片缓存等。

  ReferenceQueue softQueue = new ReferenceQueue();

  SoftReference<string> softRef = new SoftReference<string>(new String("软引用"), softQueue);

  通过softRef.get()方法可以取到这个对象,当这个对象被标记为需要回收的对象时,则返回null;

  3、弱引用:

  无论内存是否充足,JVM进行垃圾回收时都会被回收(但如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象,软引用也是如此)。

  ReferenceQueue weakQueue = new ReferenceQueue();

  WeakReference<string> weakReference = new WeakReference<string>(new String("弱引用"),weakQueue);

  4、虚引用:

  跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收,也无法通过虚引用来取得一个对象实例。唯一目的是在这个对象被回收时收到一个系统通知。

  ReferenceQueue phantomQueue = new ReferenceQueue();

  PhantomReference<string> phantomReference = new PhantomReference<string>(new String("虚引用"), phantomQueue);

  phantomReference.get();//永远返回null

  phantomReference.isEnQueued();//返回是否从内存中已经删除

  虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。虚引用主要用于检测对象是否已经从内存中删除。

  参考连接:

https://bbs.csdn.net/topics/390502534

https://www.cnblogs.com/gudi/p/6403953.html

https://www.cnblogs.com/dolphin0520/p/3784171.html

https://www.2cto.com/kf/201609/548593.html

原文地址:https://www.cnblogs.com/zjxiang/p/9218208.html

时间: 2024-10-22 16:19:35

JVM理论:(二/2)判断对象是否已死的相关文章

JVM的判断对象是否已死和四种垃圾回收算法总结

面试题一:判断对象是否已死 判断对象是否已死就是找出哪些对象是已经死掉的,以后不会再用到的,就像地上有废纸.饮料瓶和百元大钞,扫地前要先判断出地上废纸和饮料瓶是垃圾,百元大钞不是垃圾.判断对象是否已死有引用计数算法和可达性分析算法. 1.引用计数算法 给每一个对象添加一个引用计数器,每当有一个地方引用它时,计数器值加 1:每当有一个地方不再引用它时,计数器值减 1,这样只要计数器的值不为 0,就说明还有地方引用它,它就不是无用的对象.如下图,对象 2 有 1 个引用,它的引用计数器值为 1,对象

JVM——对象已“死”的判定

主要针对Java堆和方法区 1.判断对象是否已"死" Java堆中存放着几乎所有的对象实例,垃圾回收器在对堆进行回收之前,首先应该判断这些对象哪些还"存活",哪些已经"死亡". (1)引用计数法 A. 工作流程 给每个对象附加一个计数器,每当有一个地方引用此对象.计数器+1:每当有一个地方不再引用此对象,计数器-1:在任意时刻,只要对象引用计数器值为0,任务此对象已经"死亡".(没有"死亡"的对象一定不会被

JVM高级特性与实践(二):对象存活判定算法(引用) 与 回收

关于垃圾回收器GC(Garbage Collection),多数人意味它是Java语言的伴生产物.事实上,GC的历史远比Java悠远,于1960年诞生在MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.当Lisp尚在胚胎时期,开发人员就在思考GC需要完成的3件事情: 哪些内存需要回收? 什么时候回收? 如何回收? 目前GC早已解决了以上问题,内存的动态分配与内存回收机制已经相当成熟,一切似乎“自动化”起来.而开发人员仍旧需要了解GC和内存分配等底层知识,因为在排查各种内存溢出.内

JVM如何判断对象能否被回收

•写在前面 说起Java和C++,很容易想到让人疯狂的指针,Java使用了内存动态分配和垃圾回收技术,让我们从C++的各种指针问题中摆脱出来,更加专心于业务逻辑,不过如果我们需要深入了解java的JVM相关原理,我们必须要面对这些东西,深入了解JVM在内存动态分配和垃圾回收技术的原理知识,这篇文章就是来做一个先导,在jvm进行垃圾回收之前,它必须要知道回收的对象是否已“死”,这样才能保证程序的正常稳定. •对象的创建 我们将回收对象前,先讲讲在虚拟机上,对象是怎么被创建的.在我们编写代码的角度(

Oracle——判断对象是否存在(未完工)

一.系统表: 1.User_Tables:存储用户下的所有表的信息: 2.dba_tables:存储管理员权限下的所有表的信息: 3.all_tables:存储所有表的信息. 二.判断对象是否存在 1.判断表 我们只能通过使用select count(*) 的方式判断当前表是否存在,返回1则代表存在,0则代表不存在,例如: SELECT COUNT(*) FROM User_Tables WHERE table_name = 'CODE_BMDM';(在SQL中使用这种方法亦可)需要注意的是:表

JVM【第十回】:【判断对象已死之引用计数算法】

很多教科书判断对象是否存活的算法是这样的:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器都为0的对象就是不可能再被使用.很多应届生和一些有多年工作经验的开发人员,他们对于这个问题给予的都是这个答案. 客观地说,引用计数算法的实现建安,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软COM(Component Object Model)技术.使用ActionScript3的FlashPlayer

JVM【第十一回】:【判断对象已死之根搜索算法】

在主流的商用程序语言中(Java和C#)都是使用根搜索算法(GC Roots Tracing)判断对象是否存活的.这个算法的基本思路:通过一系列的名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(就是从GC Roots到这个对象不可达)时,则证明对象是不可用的.如下图所示,对象object5.object6.object7虽然互相有关联,但是它们到GC Root

JVM学习记录-对象已死吗

前言 先来回顾一下,在jvm运行时数据区,分为两部分,一个部分是线程共享区,主要包括堆和方法区,另一部是线程私有区分包括本地方法栈,虚拟机栈和程序计数器.在线程私有部分的三个区域是随着线程生和灭的.栈中的栈帧随着方法的进入和退出而执行着出栈和入栈操作.每一个栈帧所用内存大小在类结构确定下来时就已知了.因此这线程私有区的内存分配和回收都具备确定性,简单概括的说:这部分内存在类加载时分配,在线程结束时回收.(个人理解) 而线程共享区(堆和方法区)则不一样,一个方法中的多个分支需要的内存可能不一样,只

JVM高级特性-三、垃圾收集之判断对象存活算法

一.概述 运行时数据区中,程序计数器.虚拟机栈.本地方法栈都是随线程而生随线程而灭的 因此,他们的内存分配和回收是确定的,在方法或线程结束时就回收.而Java堆和方 法区则是不确定的,程序运行过程中创建对象的大小是不定的,只有在程序处于运行 期才能知道所需内存的大小 二.“存活算法” 要判断对象是否存活,主要有两种算法:引用计数法和可达性分析算法 引用计数法 引用计数法就是给对象加上一个引用计数器,每当对象被 引用一次 计数器值就加1,引用时效则减1,计数器为0则表示不会再被使用. 可达性分析算