内存回收

收集器
    JVM通过GC来回收堆和方法区的内存,GC的基本原理首先会找到程序中不再被使用的对象,然后回收这些对象所占用的内存,通常采用收集器的方式实现GC,主要的收集器有引用计数收集器和跟踪收集器。
1、引用技术收集器
    引用计数器在每次的对象赋值是进行引用计数器的加减,它有一定的消耗。另外,引用计数器对于循环的场景没有方法实现回收。(不用)  
2、跟踪收集器
    跟踪收集器采用的为集中式的管理方式,全局记录数据的引用状态。基于一定条件的触发(例如定时。空间不足时),执行时需要从根集合来扫描对象的引用关系,这可能造成程序的暂停,主要有复制(copying)、标记-清除(Mark-Sweep)和标记-压缩(Mark-Compact)三种实现算法。
    复制
    复制采用的方式为从根集合扫描出存活的对象,并将找到的存活对象复制到一块新的完全未使用的空间中。
    复制收集器方式仅需从跟集合扫描所有存活的对象,当要回收的空间中存活对象比较少时,复制算法会比较高效,其带来的成本是要增加一块内存空间进行对象的移动。
    标记-清除  
    标记-清除采用的方式为从跟集合开始扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象,并进行回收。
    标记-清除动作不需要进行对象的移动,且仅对其不存活的对象进行处理。在空间中存活的对象较多的情况下较为高效,但由于标记-清除采用的为直接回收不存活对象所占用的内存,因此会造成内存碎片。
    标记-压缩
    标记-压缩采用和标记-清除一样的方式对存活的对象进行标记,但在清除时则不同。在回收不存活对象所占用的内存空间后,会将其他所有存活对象都往左端空闲的空间进行移动,并更新引用其对象的指针。
    标记-压缩在标记-清除的基础上还须进行对象的移动,成本相对更高,好处则是不产生内存碎片。

    SUN JDK中可用的GC
    SUN JDK根据运行的Java程序进行分析,认为程序中大部分对象的存活时间都是较短的,少部分对象是长期存活的。基于这个分析,SUN JDK将JVM堆划分了新生代和旧生代,并基于新生代和旧生代中对象存活时间的特征提供了不同的GC实现。




根集合对象:当前运行线程的栈上引用的对象、常量及静态变量、传到本地方法中,还没有被    本地方法释放的对象引用。

如果Minor GC仅从以上这些根集合对象中扫描新生代的存活对象,则当旧生代中的对象引用了新生代的对象是会出现问题,但旧生代通常比较大。为了提高性能,不可能每次Minor GC的时候去扫描整个旧生代,SUN JDK采用了remember set的方式来解决这个问题。
    SUN JDK在进行对象赋值时,如果发现赋值的为一个对象引用,则产生write barrier,然后检查需要赋值的对象是否在旧生代及赋值的对象引用是否指向新生代:如果满足条件,则在remember set做个标记,SUN JDK采用了Card Table来实现remember set。


新生代可用的GC:串行GC(serial gc)、并行回收GC(Parallel Scavenge)、并行GC(ParNew)
旧生代和持久代可用GC:串行、并行、并发

猜你喜欢

转载自guoshaobin.iteye.com/blog/2245406