Notes: Garbage Collection in Java(Java的自动垃圾回收机制)

来源:互联网 发布:福建弘扬软件怎么样 编辑:程序博客网 时间:2024/05/05 23:05

Java与C++的规定不同的地方:

1)C++不允许在类成员定义的时候初始化;Java可以

2)C++允许创建局部对象(存在栈上的对象),函数调用结束后回收;Java只能创建堆的对象,以为Java只能用new()来创建。

3) C++需要自己去free之前new()出来的对象,否则就算指向它的指针被回收/ 销毁了,它还会一直在那里。但Java,JVM有自动的回收机制。你可以用System.gc()去激活它,或者让JVM在内存不够的时候主动去激活它。注意,一般内存够用的时候,JVM并不会主动去激活它。回收的对象是不再有有效引用指向它的对象。为什么说是有效引用?是为了排除循环引用的情况(我的引用作为你的类成员,而我的类成员有你的引用,但除此之外,再也没有别的引用)。


这篇文章详细介绍JVM的自动垃圾回收机制:


Java调用垃圾回收的策略是只要程序没有到濒临内存耗尽的情况,Java就不去激活自动垃圾回收。而待程序运行结束后,统一将这些内存资源交还给系统。这个策略的好处在于,垃圾回收也是需要耗用资源的,这样能减少它对资源的使用。

但有一点需要注意的,垃圾回收的对象仅仅在于回收new出来的没有有效引用的对象内存,无法回收那些并非通过new创建的特殊内存。


垃圾的步骤是:


调用finialize()方法,然后在下一次的垃圾回收动作发生时,才真正回收对象占用的内存。

finialize()的意义是:

1)调用finialize的目的是让程序员自定义销毁并非通过new创建的特殊内存。这些特殊内存指的是,采用了类似C语言的方法(本地)去分配的内存。本地方法是Java调用非Java代码的方式。支持C和C++。

2)在销毁对象前做的检查,例如确认所有文件I/O已关闭。


这里提一个良好的编程习惯:我们应该总是假设基类版本的finialize()也在做某些重要的事情,所以要用super来调用基类的finialize()函数。但需要添加异常处理来添加这个句子。


垃圾检测方法:

1)引用计数法:简单,但速度慢。每个对象赋予一个引用计数器,多一个引用指向它就+1. 当引用被销毁(离开作用域,方法中的局部变量)或者置Null的时候,-1. 在程序的整个生命周期都需要维护这个引用数列表,不停地遍历这个表,发现有0的时候,立即释放对象。同时,这个方法无法应对“循环引用”的问题。

2)可达性分析算法:对任何一个“活”的对象,必能在堆、栈以及静态区中找到指向它的引用。所以,反之而言,我们可以直接遍历堆、栈以及静态区的所有引用,找到它们指向的对象,都列为活对象。具体而言,从一系列成为“GC Roots"的引用作为起点,向下搜索,能被这些引用链设计的对象都是活的。反之,则是可回收的。


垃圾回收方法:

1) 停止-复制 (stop - copy),它不是后台回收模式,因为它需要暂停程序。

先暂停程序的运行,将所有检测到的”活“对象都复制到另一个堆空间(块),没被复制的都是垃圾。当对象被复制到新堆时,他们必须是紧凑的(整理)。然而,这个方法需要维护两个堆,而且复制之后,还需要遍历修改引用,比较麻烦。如果产生的垃圾很少的时候,这个方法显得笨重。

2)所以,一般应对垃圾较少的时候,JVM采用的另一种回收办法:标记-清扫(mark - and - sweep)。它遇到很多垃圾的时候性能不如停止-复制。但是,少量垃圾时,它是教好的选择。方法简述为,遍历在堆、栈与静态区的引用,找出活对象时,标记一下,不做任何回收。完成遍历后,开始清理,得到一个不连续的堆空间,再对堆空间进行整理 (操作系统领域称之为内存压缩)。这个方法也需要暂停程序,所以不是后台回收模式。








0 0
原创粉丝点击