Java垃圾回收(GC)机制总结

版权声明:转载请注明转载地址。 https://blog.csdn.net/qq_36144187/article/details/81537751

概述

          本文汇总了垃圾回收(GC)相关知识,精炼了部分理解复杂的部分,可能会忽略某些特殊情况,是对GC的总体整理分析。

哪些区域需要回收?

          java内存可大体分为:方法区,堆(heap),虚拟机区,本地方法栈,程序计数器(PC),这五块。虚拟机区,本地方法栈,程序计数器(PC)与具体线程绑定,生命周期和线程相同,某个线程回收时,与此线程绑定三块区域内存同时回收。而方法区,堆(heap)是由所有线程共用。同时也是java程序内存使用的大部分,存放着类和对象。

          java的GC针对的是:方法区和堆区域的内存回收。

如何知道哪些对象需要回收?

          1.引用计数法:给对象添加一个引用计数器,当增加一个引用时+1,引用失效时-1.为0则清除。

                     注意:出现形似于下图的引用关系(循环引用)时,当棕色的引用消失时,从逻辑上不再对小圆引用,但是所有的小圆的引用计数仍都为1,所以都不会清除。这种情形引用计数法就捉襟见肘。

                            

                  

          2. 可达性法分析:首先认为Root开始搜索,如果没有搜索到则认为不可达,则该对象逻辑上不再被使用,需要清除。Root的数目并不止一个,需要一个 GC Root Set 去保证 仍需要使用的对象不会被清除。

           可被选为GC Roots Set的对象有以下四种

                      1.栈帧中的本地表量表(应是局部表量表)中的引用对象。(我认为,此处《深入理解JVM》叫法有误)

                      2.方法区中的类静态属性引用的对象。

                      3.方法去中常量引用的对象。

                      4.本地方法栈中JNI引用的对象。

         3.四种引用分析https://blog.csdn.net/qq_36144187/article/details/81564747

类的回收:

        需要同时满足下列三个条件,才有可能被回收,仅仅是有可能。

                1.该类的所有实例都已经被回收。

                2.加载该类的ClassLoader被回收

                3.对应的java.lang.Class 对象没有在任何地方被引用。

基础垃圾收集算法

       1.标记--清除算法

               分为两个阶段,标记出需要回收的对象,然后回收。

               缺点:会产生大量的碎片,容易触发更多次的GC。

       2.标记--整理算法

               分为两个阶段,标记存活的对象,然后把存活移动到一段,回收所有边界之外的内存。

               缺点:单次的GC时间更长,

       3.复制算法

               将内存划为大小完全一样的两块内存,只是用其中的一块,每次gc就将所有存货对象,移到另一块,清除本块内存。

               缺点:会浪费50%的内存

垃圾收集基本思想

        1.分代思想:把堆分为新生代,老年代,s0,s1这四块。不同的区域使用不同的算法。一般对象分配在新生代,当新生代满触发 Minor GC。若对象可以s区域,则移入s区域,这个区域采用复制算法,多次仍存在,则移入老年代,老年代满触发 Major GC。或者大对象直接在老年代分配。Full GC 则是对整个堆进行GC操作。

        2.Stop-The-World:就是全局停顿,因为当内存在被使用时,总是会产生垃圾,若一边清理一边运行,那么垃圾总是清理不干净,更重要的是标记--整理算法将无法使用。

综合垃圾收集器

        1.串行收集器(SerialGC):

                   1.最古老,最稳定

                   2.可能会产生较长时间的停顿

                   3. -XX:+UseSerialGC

                            - 新生代,老年代使用串行回收

                            - 新生代复制算法

                            - 老年代标记-压缩

          2.ParNew:

                   1.新生代并行,老年代串行。

                   2.可以理解为Serial在新生代的并行版本

                   3. -XX:+UseSerialGC

                            - 多线程支持多核

                            -  -XX:ParallelGCThreads 限制线程数量

                            - 基本和串行收集器一致

       

           3.CMS收集器

                   1.停顿时间短,清理不能完全干净

                   2.采用标记-清除算法

                   3.不能在快满的使用

                   4. -XX:+UseConcurrentMarkSweepGC

                            - 并发阶段会降低吞吐量

                            -  针对老年代

                            - 新生代仍用ParNew

                   5.工作流程:

                            -初始标记:根可以直接关联到的对象

                            -并发标记:一边运行一边标记全部对象

                            -重新标记:产生 Stop The world ,修正并发标记

                            -并发清除:基于标记结果直接清理对象

           4.G1收集器

                   1.取消新生代老年代的物理隔离,使用大小相同的Region分割堆。

                   2.停顿时间可以预测控制

                   3.整体上采用标记-整理,局部来看采用两个Region之间的复制算法

                   4. -XX:+UseConcurrentMarkSweepGC

                            - 优化了大于4G以上的超大堆

                            -  充分利用Cpu和多核环境,适合现代的算法

                            - 增加了与 Region关联的 Remembered Set 避免全堆扫描

                   5.工作流程:与CMS流程大致相同。

总结                          

             内存回收和垃圾收集器虽然影响程序的并发性,吞吐率。但仍需一个良好的程序才能发挥调优的作用。同时没有固定的收集器、参数的组合,只能针对不同的程序调优。

             本文引用:

                    《深入理解JVM》   周志明

                      炼数成精   JVM相关课程

                      http://blog.jobbole.com/109170/       

猜你喜欢

转载自blog.csdn.net/qq_36144187/article/details/81537751