美文网首页
jvm垃圾回收器

jvm垃圾回收器

作者: 过去今天和未来 | 来源:发表于2017-11-25 17:30 被阅读22次

    哪些内存需要回收

      java堆中存放着几乎所有对象实例,垃圾收集器在堆进行回收前,判断哪些对象还存活着。

    1.引用计数算法

          给对象添加一个引用计数器,当有一个地方引用它,计数器加1,引用失效时,计数器就减1,计数器为0的对象就不可能被使用。优点:算法简单,效率高,但当存货对象相互引用就解决不了。所以Java中GC没有采用引用计数法来管理内存

    2.可达性分析算法

         以GC Roots对象作为起始点,从这些节点依次向下搜索,如果当前对象到GC Roots没有任何路径相连时,那么当前对象没有引用。

        可做GC Roots的对象1.java虚拟机栈中引用的对象 2.本地方法栈中引用的对象 3.方法区中的常量引用的对象 4.方法区中静态属性引用的对象。当对象不可达,并不是宣告对象死亡,还有对象进行最后自我救赎--finalize。java允许使用finalize方法在垃圾收集器将对象从内存中清楚之前做必要清理工作。这个操作中如果对象被重新引用,对象就可以活过来了。

         判断对象是否有必要执行该方法主要有以下两个依据:对象有没有覆盖finalize方法;对象已覆盖finalize方法,检查finalize方法是否被虚拟机调用过,如果已被调用,就不需要再次执行。

    何时回收

        young gc触发条件似乎要简单很多,当 eden 区的内存不够时,就会触发young gc

    full gc

    1. old gen 空间不足

           当创建一个大对象、大数组时,eden 区不足以分配这么大的空间,会尝试在old gen 中分配,如果这时 old gen 空间也不足时,会触发 full gc,为了避免上述导致的 full gc,调优时应尽量让对象在 young gc 时就能够被回收,还有不要创建过大的对象和数组。

    2. 统计得到的 young gc 晋升到 old gen的对象平均总大小大于old gen 的剩余空间

           当准备触发一次 young gc时,会判断这次 young gc 是否安全,这里所谓的安全是当前老年代的剩余空间可以容纳之前 young gc 晋升对象的平均大小,或者可以容纳 young gen 的全部对象,如果结果是不安全的,就不会执行这次 young gc,转而执行一次 full gc

    3. perm gen 空间不足

         如果有perm gen的话,当系统中要加载的类、反射的类和调用的方法较多,而且perm gen没有足够空间时,也会触发一次 full gc

    4. ygc出现 promotion failure

          promotion failure 发生在 young gc 阶段,即 cms 的 ParNewGC,当对象的gc年龄达到阈值时,或者 eden 的 to 区放不下时,会把该对象复制到 old gen,如果 old gen 空间不足时,会发生 promotion failure,并接下去触发full gc

    如何回收

    标记-清除算法

         标记清除算法分为”标记“和”清除“两个阶段:首先标记处所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

    它的不足有两个:1.效率问题,标记和清除两个过程的效率都不高。2.空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后的程序在运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

    复制算法

          为了解决效率问题,”复制“算法出现了,将可用的内存划分为两块,每次只使用其中一块, 当这一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。这样就不用考虑内存碎片等复杂情况。现在的商业虚拟机都采用这这种收集算法来回收新生代。根据研究表明,新生代中98%的对象都是”朝生夕死“的,所以新生代中将内存分为一块较大的Eden空间和两块较小的Survivor空间(from和to),每次使用Eden和其中一块Survivor,当回收时,将Eden和刚才用过的Survivor中还存活的对象一次性的复制到另外一个Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。

          Hotspot虚拟机默认使用Eden和Survivor的大小比例是8:1,也就是Eden占8,form和to各占1.当Survivor空间不够的时候,需要依赖老年代进行分配担保。在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果大于,则此次Minor GC是安全的;如果小于,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果HandlePromotionFailure=true,那么会继续检查老年代最大可用连续空间是否大于历次晋升到老年代的对象的平均大小,如果大于,则尝试进行一次Minor GC,但这次Minor GC依然是有风险的;如果小于或者HandlePromotionFailure=false,则改为进行一次Full GC。

    标记-整理算法

         标记整理算法的“标记”过程和标记-清除算法一致,只是后面并不是直接对可回收对象进行整理,而是让所有存活的对象都向一段移动,然后直接清理掉端边界以外的内存。

    分代收集算法

          当前商业虚拟机的垃圾收集都采用”分代收集“算法,其主要思想是将Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适合的收集算法。

          在新生代采用复制算法,上面已经讲过了。而老年代因为对象存活率高,没有额外空间为它进行分配担保,就必须使用”标记清理“或者”标记整理“算法来进行回收。

    面试题

    1.你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms,包括原理,流程,优缺点?

          串行垃圾收集器:收集时间长,停顿时间久(单线程收集器,它进行垃圾收集时,暂停其他所有工作的线程,直到收集结束)

          并发垃圾收集器:碎片空间多(使用多线程来通过扫描并压缩堆,可以大幅度压缩停顿时间)

          CMS收集器:主要基于标记-清除算法实现,使用多线程算法去扫描并发现未使用的对象进行回收,初始标记(标记GC Roots直接关联的对象)、并发标记、并发预清理、并发清除、并发重置.

          G1收集器:主要步骤:初始标记,并发标记,重新标记,复制清除(整理)它是“标记-整理”算法实现的收集器

          CMS的缺点是对cpu的要求比较高。G1是将内存化成了多块,所有对内段的大小有很大的要求

          CMS是清除,所以会存在很多的内存碎片。G1是整理,所以碎片空间较小

    2..垃圾回收算法

        引用计数,增加一个字段来标记当前应用次数,引用计数为0就可以GC,但不能解决循环引用的问题

        可达性:通过一系列GC Root的对象作为起点,向下搜索,搜索所有没有与当前对象GC ROOT有引用关系的对象,这是对象就可以GC

    相关文章

      网友评论

          本文标题:jvm垃圾回收器

          本文链接:https://www.haomeiwen.com/subject/hevcbxtx.html