附上一篇垃圾回收算法详解
优点:a.不需要考虑内存管理, b.可以有效的防止内存泄漏,有效的利用可使用的内存, c.由于有垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"
原理:垃圾回收器是作为一个单独的低级别的线程运行,在不可知的情况下对内存堆中已死亡的或者长期没有使用的对象回收,但是不能实时的对某一对象或者所有对象进行垃圾回收。
垃圾回收机制:分代复制垃圾回收、标记垃圾回收、增量垃圾回收
GC(Gabage Collection)工作原理:当创建对象时,GC就开始监视这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理heap(堆)中的素有对象。通过这种方式确定哪些对象是“可达的”,哪些是“不可以达的”。
垃圾回收机制通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清理,我们虽然可以调用System.gc()让垃圾回收器运行,但依旧无法保证GC一定会执行。
1.垃圾回收机制的目标是回收无用对象的内存空间(记住:不是对象),这些内存空间是JVM堆内存的内存空间。垃圾回收只回收内存资源,对于那些物理资源,如数据库连接,Socket,I/O流等资源无能无能为力,我们要自己关闭回收。
2.为了加快垃圾回收机制回收那些无用对象所占的内存空间,我们可以讲对象的引用变量置于null(记住:置于null后,垃圾回收机制不会立即执行的)。
3.垃圾回收机制的潜在缺点它的开销会影响性能。Java虚拟机必须跟踪程序中有用的对象才可以确定哪些对象时无用的,并释放那些无用对象所占的内存空间。这个过程要处花费处理器时间的。
4.垃圾回收的不可预知性。我们可以通过Runtime对象的gc()方法或者System.gc()的方法来建议系统进行垃圾回收,但我们不能精确控制垃圾回收机制的运行。==================================================================================================
首先我们要明白两个问题:
在java中是通过引用来和对象进行关联的,也就是说如果要操作对象,必须通过引用来进行。那么就可以通过一个简单的方法引用计数来判断一个对象是否被回收,假如一个对象没有任何的一个引用与之关联,则该对象基本不大可能在其他地方被引用到,那个这个对象就可能成为被回收的对象。
该方法实现简单,且效率高。但是,该方法也存在一定的缺点,无法解决循环引用的方法。什么是循环引用?给一段代码展示
public class App{
public static void main(String[] args) {
Test object1 = new Test();
Test object2 = new Test();
object1.object = object2;
object2.object = object1;
object1 = null;
object2 = null;
}
}
class Test{
public Test object = null;
}
虽然最后两句将object1和object2置为null,但是他们由于互相引用,结果导致它们的计数都不为0,那些垃圾收集器就无法回收它们.
所以为了解决这个问题,java中采取了可达性分析法。该方法的基本思想是通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。
这种方法相比引用计数方就更加严谨了,并且可能解决循环引用的问题。
在回答这个问题之前,我们先了解下目前垃圾回收有哪几种主流的回收算法.
1).Mark-Sweep(标记-清除)算法
这是最基础的算法,该算法就是标记出需要被回收的对象,等到需要执行GC操作时将标记的对象一并清除,实现垃圾回收。改方法简单,效率高,但是有个缺点就是会导致内存碎片。
2).Copying(复制)算法
Copying算法是将内存区域划分为两块相同大小的子区域,并且在其中的一块中执行对象分配,等到这一块的内存用完了,就将该区域还存活着的对象复制到另外一块内存区域上面,然后再把已使用的内存空间一次清理掉,这样就不会导致内存碎片的问题,但是有个明显的缺点,每次只能使用到一半的内存,对内存压力大。
3).Mark-Compact(标记-整理)算法
Mark-Compact算法是在Mark-Sweep算法的基础上进行了改进,算法标记跟Mark-Sweep一样,只是在标记完之后,将标记的对象向一端移动,然后清理掉边界以外的内存区域,这样就解决了内存碎片化的问题
3).Generational Collection(分代收集)算法
这是目前Jvm使用的垃圾回收算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。分为老年代(Tenured Generation)和新生代(Young Generation)。老年代的内存区域的对象一般回收频率比较低,采用了Mark-Compact算法,而新生代的内存区域由于每次需要回收大量对象,回收频率较高,所以将该区域又划分成了一个较大的Eden空间和两个较小的Suivivor空间,每次使用Eden空间和一个Survivor空间的,当需要回收垃圾时,将Eden空间和该Survivor空间的存活对象复制到另外一块Survivor空间上,然后清理到Eden和刚才使用的Survivor空间,实现垃圾回收机制.
所以java垃圾回收机制主要关注的重点是可达性分析法还有分代收集算法,并且了解它们的优点。