JVM(3)--垃圾收集

来源:互联网 发布:国网内网网络大学地址 编辑:程序博客网 时间:2024/06/11 18:40

垃圾收集设计到算法和源码,这里只在概念上进行总结:
根据上一篇文章的内容,我们知道方法区和堆是垃圾收集的对象。这其中,方法区是类信息,堆是对象数据。对堆的收集更为频繁和有效,而方法区中的垃圾收集条件严格,收集的成功率也不高。但是方法区中的类信息,由于现在的J2EE大量使用反射,自定义ClassLoader等,使得方法区的信息频繁的加载,所以卸载也是必须的!


垃圾收集的思路

  1. 老的思路是计数器,在创建一个对象时为这个对象计数1,引用这个对象时计数器+1,当计数器为0时该对象即可被垃圾收集。但是存在的问题是两个对象相互引用,像死锁一样永远无法收集。
  2. 目前的垃圾收集都采用跟踪搜索思路。即从根开始遍历所有对象,若处在树中那就是被引用,否则的话都可以垃圾回收。

垃圾回收的基础算法

  1. 标记-清除,采用搜索跟踪,所有被引用的对象被标记,搜索完成后,未被标记的对象即被清除。缺点:清除后可能产生堆碎片。
  2. 复制,复制不进行标记,而是搜索跟踪后把被引用的对象复制到一块新的内存堆中。原内存堆即整体释放。这样不会产生碎片。缺点:需要一块新空间来完成复制。
  3. 标记-整理,即在标记-清除后,主动的移动对象以保证空间的连续性。

垃圾回收的实际应用思路–结合基础算法加上一定的策略用于实际中

  1. 分代:JVM会将对象分成不同的代并存放在特定的内存区域。在垃圾收集时,可以对这些区域应用不同的收集频率和收集算法。目标就是要提高性能。
    1.1所有新生成的对象,都属于young generation(新生代,年轻代)。但是,这些对象有的很容易消亡,如程序中的string对象;有的却需要存活很长时间,如用户session。
    1.2如果一个新生代对象在经过数次垃圾回收后仍存在,就进入年老代,tenured generation。具体如何进入,有一定的算法。有兴趣可以去搜索。
    1.3通常会给年轻代的内存区设立一个尺寸大小,但是年老代无法设立尺寸大小,因为对象不被垃圾收集的话只能不断的涌入年老代。

  2. 渐进收集:或者说是部分收集。垃圾收集大部分使用的是stop the world即暂停所有线程来执行垃圾收集。那么如果暂停的时间太长,势必影响到程序实时性。所以,需要在限定的时间内收集限定的区域并切换回程序线程,保证实时性用户体验。
    2.1因为年轻代的区域尺寸固定,《深入JAVA虚拟机》给出的说法是“收集器可以大体上保证在一个最大时间值内【渐进】的收集所有对象”。(意思就是不复杂不需要特别的设计?)
    2.2由于年老代区域可能会很大,所以需要使用火车算法来给出固定的长度,每次只收集固定部分的垃圾。
    2.3注意这个固定时间并不是严格保证的,因为万一一块区域内的垃圾很多,也还是要等收集工作做完才会切换回程序线程。


构造专门的对象配合垃圾收集
我们明白了垃圾收集的机制后,有什么用呢?一个典型的应用就是缓存,我们在一块内存空间中缓存一些对象,就像一个池子一样。 这个缓存池里什么数据应该存在什么数据应该清理呢?这就需要垃圾收集能以我们预期的方式去运作。Java构造了专门的对象来帮助我们实现这种运作。

  1. 强引用,在程序编写时最常见的引用。一个对象直接的持有另一个对象就是强引用,强引用不能被垃圾收集。

    **问题来了,缓存中的对象如果被强引用了,不能被收集,一些个使用频率特别少的对象,却始终占据缓存空间。那么缓存就不划算了。

  2. 软引用。SoftReference sr = new SoftReference(Object)。缓存可以把刚才提到的那些对象设置为软引用。垃圾回收器可以自行决定何时回收这些对象,在缓存空间OOM时,则必须回收这些对象。
    **注意,回收是指把Object变为不可触及,进而回收Object。回收后sr.get()就会得到null。

  3. 弱引用。对于一些优先级更低的对象,可以使用弱引用。弱引用指向的Object会在垃圾回收发现时直接清除。 WeakHashMap就是一个结合弱引用机制的设计。

  4. 虚引用,幽灵引用。PhantomReference。虚引用的目的和软、弱引用不同,不是为了告诉GC这个引用的Object可以被删除。一个对象被虚引用了,就和不存在这种引用一样,GC对待这个对象和对待普通对象没区别。
    唯一的区别就是,虚引用的目的是必须要实现这个引用的clear()方法,而GC在回收对象时必须调用clear()方法,所以程序员可以利用这点做一些深度的清理工作。

ps:尽量不要使用finalize方法,原因是因为,垃圾收集器在任何情况下,都不能保证finalize会马上执行,甚至会执行,而在finalize中有可能会被逃逸。finalize方法本身也存在严重的性能问题。

0 0
原创粉丝点击