垃圾回收器概述

垃圾回收要考虑的问题

1、那些内存需要回收?

2、什么时候回收?

3、如何回收?

如何判断对象"已死"?

一、Reference Counting ---- 引用计数法

1、算法思想

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

2、采用这种方式的案例

微软的COM技术,使用ActionScript的Flash Player,Python语言以及Squirrel脚本

3、特点

实现简单,效率很高,但是主流的java 虚拟机没有采用这种方式,因为它无法解决循环引用的问题。

public class ReferenceCountingGC {

	public Object instance = null;
	private static final int _1MB = 1024 * 1024;

	// 这个属性的作用就是占点内存,以便在GC 日志中查看内存是否被回收
	private byte[] bigSize = new byte[2 * _1MB];

	public void testGC() {
		ReferenceCountingGC referenceCountingGC1 = new ReferenceCountingGC();
		ReferenceCountingGC referenceCountingGC2 = new ReferenceCountingGC();

		//循环引用
		referenceCountingGC1.instance = referenceCountingGC2;
		referenceCountingGC2.instance = referenceCountingGC1;

		referenceCountingGC1 = null;
		referenceCountingGC2 = null;

		System.gc();
	}

	public static void main(String[] args) {
		new ReferenceCountingGC().testGC();
	}
}
[GC (System.gc()) [PSYoungGen: 8141K->2720K(38400K)] 8141K->2728K(125952K), 0.0041620 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 2720K->0K(38400K)] [ParOldGen: 8K->2557K(87552K)] 2728K->2557K(125952K), [Metaspace: 2470K->2470K(1056768K)], 0.0063053 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]

虚拟机并没有因为这两个对象互相引用就不回收他们,说明虚拟机并不是采用引用计数法来判断对象是否存活的。

二、Reachability Analysis可达性分析算法

在主流的商用程序语言中,java,c#,Lisp,都是采用可达性分析算法来判断一个对象是不是存活的。

1、算法思想

通过一系列的称为GC Roots对象作为起始点,从这些结点开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连的时候(也就是图论的GC roots 到这个对象不可达)时,则这个对象是不可达的。

2、采用这种方式的案例

Java,c#,Lisp等语言

3、Java中可作为GC Roots的对象

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

三、关于引用

无论是引用计数法还是可达性分析算法,都是通过引用来判断对象是否存活。

JDK 1.2 之后,java对引用的概念进行了扩从,详细介绍如下。

1、强引用(Strong Reference)

在程序代码中普遍存在的引用,类似 Object object = new Object(),这类都是强引用。只要强引用存在,垃圾回收器永远不会回收掉被引用的对象。

2、软引用(Soft Reference)

描述一些还有用但不是必须的对象。对于软引用关联的对象,在系统将要发生内存溢出之前,将会把这些对象列进回收范围之中进行第二次回收,如果回收还没有足够的内存,才会抛出oom异常。Java提供了SoftReference类来实现软引用。

3、弱引用(Weak Reference)

也是用来描述非必须对象,但是强度比软引用还要弱一些,被若引用关联的对象只能生存到下一次垃圾回收之前。当垃圾回收器工作时,无论当前内存是否足够,都会回收掉只被若引用关联的对象。Java提供了WeakReference类实现弱引用。

4、虚引用(Phantom Reference)

也称幽灵引用或者幻影引用。是最弱的一种引用关系。一个对象是否有弱引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获得一个对象的实例。为一个对象设置虚引用的唯一目的是就是能在这个对象被垃圾回收器回收之前收到一个系统通知。Java 提供了PhantomReference类实现虚引用。

四、生存还是死亡

不可达的对象是不是就一定会死亡,被回收?

不是。一个对象要真正宣告死亡,至少要经历两次标记过程。

第一次标记 :如果对象在进行可达性分析算法之后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机都认为这两种情况被有必要执行被判定死亡。

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

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

注意:任何对象的finalize()方法都只会被系统自动调用一次。

时间: 2024-11-29 04:34:26

垃圾回收器概述的相关文章

JVM系列(六) - JVM垃圾回收器

前言 在之前的几篇博客中,我们大致介绍了,常见的 垃圾回收算法 及 JVM 中常见的分类回收算法.这些都是从算法和规范上分析 Java 中的垃圾回收,属于方法论.在 JVM 中,垃圾回收的具体实现是由 垃圾回收器(Garbage Collector)负责. 正文 概述 在了解 垃圾回收器 之前,首先得了解一下垃圾回收器的几个名词. 1. 吞吐量 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值.比如说虚拟机总运行了 100 分钟,用户代码 时间 99 分钟,垃圾回收 时间 1 分钟,那

了解CMS(Concurrent Mark-Sweep)垃圾回收器

http://www.iteye.com/topic/1119491 1.总体介绍: CMS(Concurrent Mark-Sweep)是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器.对于要求服务器响应速度的应用上,这种垃圾回收器非常适合.在启动JVM参数加上-XX:+UseConcMarkSweepGC ,这个参数表示对于老年代的回收采用CMS.CMS采用的基础算法是:标记-清除. 2.CMS过程: 初始标记(STW initial mark) 并发标记(Concurrent mar

[Think In Java]基础拾遗1 - 对象初始化、垃圾回收器、继承、组合、代理、接口、抽象类

目录 第一章 对象导论第二章 一切都是对象第三章 操作符第四章 控制执行流程第五章 初始化与清理第六章 访问权限控制第七章 复用类第九章 接口 第一章 对象导论 1. 对象的数据位于何处? 有两种方式在内存中存放对象: (1)为了追求最大的执行速度,对象的存储空间和生命周期可以在编写程序时确定,这可以通过将对象置于堆栈或者静态存储区域内来实现.这种方式牺牲了灵活性. (2)在被称为堆的内存池中动态地创建对象.在这种方式,知道运行时才知道对象需要多少对象,它们的生命周期如何,以及它们的具体类型.

总结Java垃圾回收器的方法和原理

1. 垃圾回收只与内存有关 在Java中,我们new完对象之后,垃圾回收器负责回收无用的对象占据的内存资源.这与C++不同,在C++中,准许使用局部对象,回收对象时候,需要用到finalize()析构函数.C++的对象创建在堆栈中,而Java对象创建在堆中,所以我们创建完对象之后,Java的垃圾回收器在堆中,会自动帮我们回收垃圾,至于何时回收垃圾,我们不得而知了. 2.垃圾回收用到的方法 (1)finalize() 该方法是用来回收“特殊”的内存,而这内存不是new出来的,所以垃圾回收器无法回收

垃圾回收器设计

1利用栈对象自动释放(可以禁止析构函数就不能产生栈对象了哦 小技巧) 利用栈对象出作用域自动释放的特性构造一个空的智能指针类 2解决智能释放问题,只要这样就不用手工delete类指针了 在智能指针类的析构函数里面delete对象成员去对象里面释放垃圾指针等.. 3解决被智能指针代理的真实对象的函数的调用问题 重载->运算符,以便能直接调用这个智能指针存储的对象中的函数 或者使用代理模式不过没有重载的方法简单 4继承引用计数类,来为自身增加引用技术功能, 引用计数的++ --在智能指针里完成 #i

第5章(2) Java的垃圾回收器

终结处理 Java有垃圾回收器回收无用对象占据的内存资源.但垃圾回收器只知道释放经由new分配的内存,如果用其他的方法获得了一块"特殊"的内存区域,就需要我们自己完成清理工作.Java提供了finalize()方法来解决这一问题. finalize()方法: 工作原理:一但垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存. 其作用,换句话说就是:在你不再需要某个对象之前,如果必须执行某些动作,那么你

垃圾回收器如何确定哪些对象要回收---《深入理解java虚拟机》

垃圾回收器如何确定哪些对象要回收: 引用计数法 很多教科书判断对象是否存活的算法是这样的:给对象添加一个引用计数器,每当有一个地发引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器都为0的对象就是不可能再被使用的. 客观地说,引用技术算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软的COM技术.使用ActionScript 3 的FlashPlayer.Python语言以及在游戏脚本领域中被广泛应用的Squirrel中都

C++垃圾回收器的实现

一.简单介绍 这是一个自己写C++垃圾自己主动回收器,用到的都是标准C++语法.採用了引用计数加mark-sweep的方法.在没有循环引用的情况下,引用计数能够保证垃圾实时得到回收:对于有循环引用的情况下,计数就不能回收了,这时就要用mark-sweep的方法.事实上全然使用mark- sweep的方法也是能够的,但有了引用计数,能够回收大量的非循环引用垃圾,降低最后的mark-sweep时的工作量. 考虑到大家的15分钟阅读热情,在说细节之前,先show一下这个指针怎么使用.顺便提一下,这个指

谈一谈垃圾回收器

目的: 使用垃圾回收器的唯一原因就是:回收程序不再使用的内存. 针对的目标对象: Java的垃圾回收器会自动回收不再使用的Java对象,释放内存.但是回收的是用new创建的,分配在堆上的内存. finalize(): 那么,如果不是用这种方式创建的对象,该怎么回收?比如:Java调用了本地的c语言方法创建了个对象,那么这时,该对象不是放在堆上的.除非你手动去调用c的free()方法,否则,这个对象将永远不会被清理. Java的finalize()方法可以解决上面的问题.垃圾回收器在回收垃圾对象时