初探JVM垃圾回收算法

原由

看tij4.0关于java垃圾回收机制的相关思想和原理描述时,理解不深刻;同时希望了解现行的关于垃圾回收机制的一些算法原理和机制,故写此篇文章。以下是我认为作为一个开发人员所需要了解的java垃圾回收机制相关知识的一个程度,持续更新中....(以下的垃圾回收机制也不属于最新的,而是一些主流的GC回收机制的相关原理,如果有错误欢迎指出)

什么是垃圾回收:

jvm会自动给我们分配内存和释放内存,简单来说,jvm释放内存的过程就是垃圾回收。这里需要注意的是:垃圾回收的是垃圾对象所占用的内存。

为什么要进行垃圾回收:

1.合理利用内存,避免垃圾对象占用内存

2.避免内存溢出

垃圾回收运行机制:

1.判断什么样的对象属于垃圾对象?

    (1)引用计数法(缺点:当对象相互调用时,计数永远不为零)

    (2)根搜索算法(一说可达性算法,以一些基础的原始对象开始向下搜索,判断对象与根对象(GC)之间是否有联系,没有则为垃圾对象。)

2.GC回收机制

   (1)复制 ):将一半区域作为空余区域,先用跟搜索算法找出所有的有用对象,严格按照内存地址进行排列,存入空余区域。——浪费一半的堆空间,空间利用率低

   (2)标记-整理:遍历整个GC ROOTS,标记所有有用对象,将对象严格按照内存地址进行排列,将有用对象的内存地址之后的空间全部回收——需要遍历所有活着的对象,耗时长;需要维护对象引用地址列表

   (3)标记-清除:遍历整个GC ROOTS,标记所有有用对象,将垃圾对象直接进行回收——需要遍历所有活着的对象,耗时长;直接回收垃圾对象的内存空间,会产生不连续的内存地址,产生内存碎片。

  (4)分代回收算法(目前主流虚拟机的内存分配策略):年轻代保证10%空余空间,如果空间不够用,则将大对象存放到年老代(触发对象进入年老代的方式有多种,原文档有)。年轻代的GC机制是普通GC(Minor GC),使用的是复制算法,使用年轻代10%的空余空间进行复制,保证空间利用率(10%空间属于默认设置,可修改);年老代大多数对象属于存活时间较长的对象,不适用于使用复制算法(区别于年轻代临时对象多的情况),使用标记-整理或标记-清除算法,负责年老代GC操作的是:全局GC,Major GC, FULL GC(触发MajorGC的方法是在调用Minor GC时,先检测JVM统计数据,当历史进入年老代的对象的平均大小>年老代所剩空间时则触发)

PS:tij4.0对java垃圾回收器有一个有趣且全面的定义:“自适性的、分代的、停止-复制、标记-清扫”式垃圾回收器。一句话总结了垃圾回收器的本质。

对于开发人员的建议:

1.养成优秀的编程习惯:

(1)避免在循环体中创建对象,即使该对象占用内存空间不大。

(2)尽量及时使对象符合垃圾回收标准。

(3)不要采用过深的继承层次。

(4)访问本地变量优于访问类中的变量。

(5)通常情况下不要显示地触发GC,让JVM根据自己的机制实现。

2.年轻代空间分配问题

(1)年轻代过小(年老代过大) 导致频繁发生GC,增大系统消耗 容易让普通大文件直接进入年老代,从而更容易诱发Full GC。

(2)年轻代过大(年老大过小) 导致年老代过小,从而更容易诱发Full GC。 GC耗时增加,降低GC的效率。

(3)Eden过大(survivor过小) Minor GC时容易让普通大文件直接绕过survivor进入年老代,从而更容易诱发Full GC。 

(4)Eden过小(survivor过大) 导致GC频率升高,影响系统性能。

(5)调优策略 保证系统吞吐量优先 减少GC暂停时间优先。

3.年老代空间不足

(1)分配足够大空间给年老代。

(2)避免直接创建过大对象或者数组,否则会绕过年轻代直接进入年老代。

(3)应该使对象尽量在年轻代就被回收,或待得时间尽量久,避免过早的把对象移进年老代。

4.方法区的永久代空间不足

(1)分配足够大空间给永久代。

(2)避免创建过多的静态对象。

PS:JDK1.8已经将永久代改为元空间,相关概念有所改变,这里不进行探讨。

        方法区的永久代主要放置永久对象,即创建后则一直存在的对象。

        持久代如果满,将触发Full GC。

你可能感兴趣的:(初探JVM垃圾回收算法)