jvm 一些常用的垃圾回收器

前言

      要想了解垃圾回收器首先要先了解 引用计数算法可达性算法,还有一些 标记清除标记整理还有 标记复制 ,最后还有个分代收集

      了解这些之后才能看懂后面的!先标记一些没有被GC Root给引用对象 都会被标记当成垃圾回收    

先来看看引用计数算法:

       引用计数算法:

          简单的说就是 判断对象是否存活

          new出来的对象设置一个计数器, 谁引用了该对象该对象的寿命加1 如果寿命为0就可以被垃圾回收

          同时有的缺陷 比如A 引用了 B       B的寿命加1   相反 B 引用了 A       A 寿命加1   

          那么这就已经产生了循环 相互引用 一直都是1 时时不会被垃圾回收

          导致可能会内存泄漏内存溢出等。

      可达性算法: 目前都是用可达性算法判断对象是否存活  

        引用计数算法的缺陷就是互相调用  但可达性算法可以 解决循环调用。

      标记清除 :先标记一些没有被GC Root给引用对象 都会被标记当成垃圾回收

   优点:速度快,因为直接清除掉了无脑的清

   缺点 :会产生内存碎片 , 因为清除掉了很乱 然后再来个对象可能这些小的内存都不够用。

     内存碎片是什么?   

            内存碎片就是 当内存空间分配了大量的内存 和 释放内存就会产生一些小小的内存 这些就是些碎片

            如果还有对象要放进去那么就可能会应内存碎片而内存溢出,内存泄漏

                标记之后:

         金色表示存活的对象  灰色表示没有被引用对象称为死对象

275f0b0524574785a4074c73a7252600.jpeg

                清除之后:

c07478a2ab3c43a98bce0d5db66898e8.jpeg

        标记整理 :            

                标记之后 :

94d95a1a86da4e79911f686b93ea4b68.jpeg

                整理之后:

6b98aec90b96494e9c5700a09d09c39b.png

      

                标记整理就是 先标记 没有被GC Roots引用的对象标记起来

                然后一个个的整理 不会产生内存碎片 ,       

                     优点:不会产生一些小小的内存碎片                

                     缺点:就是要一个一个整理太耗时了或者效率不高

         标记复制 : 

  大概流程:

        标记复制 有两个部分 form 和 to (from存放一些存活的对象,to就是复制过来的对象)

        当内存不足时就会将一些没有被GC Roots(也就是不是可达性的对象)所引用的对象标记

        然后把存活的对象存入到to中  把标记的对象作为垃圾回收掉并且 from 和 to 交换位置  这时

 from就变成了to了  to就变成了from了。

           优点和缺点:

                  优点:速度快,不会产生内存碎片而内存溢出和内存泄漏

                  缺点:会造成双倍的内存,就是两个内存

     分代收集:

            当新生代内存不足时就会进行第一次Minor GC 

            把没有被GC roots (根对象 从第一个根对象找

            比如 A 引用了 B  B 引用了 C  那么就先去找A对象看看引用的对象是否被引用着)   引用的对象进行标记 当成垃圾回收 

                然后把存活的对象复制到幸存区( TO )  中 然后 To 和 From 交换位置 并且存活的对象寿命加1         

                过了一段时间后 新生代内存又不足了 进行了第二次minor GC

                把没有被引用的对象标记当成垃圾回收

                把存活的对象 复制到 To 并且寿命加1  From 和 To  交换位置                  

                如果新生代中的对象存活的时间达到了一定的岁数(比如是寿命是15 达到了晋级的要求)就会直接晋级到老年代中

                如果 老年代的垃圾又满了 就又会进行一次Old GC 垃圾回收

                又过了一段时间 新生代 、老年代、幸存区1,幸存区2内存都不足时就会进行 full GC 对整个堆内存做一次垃圾回收 从而加快运行的效率。

        串行 ( Serial GC垃圾回收器 )

              串行是一个时代过了很久的一个垃圾回收器,串行被jdk1.3所支持

              串行是一个单线程(一个人工作,一个一个回收线程的垃圾)

              串行的工作流程:

35bdeb0f8b934b4888ae1e5a24e49d0b.jpeg

                     新生代内存达到一定的阈值了就引发了垃圾回收( minor GC )把没有被GC Roots引用的对象做一个标记 之后就回收掉

                     然后复制到 幸存区当中 这时就会阻塞所有线程(STW) 之后一个垃圾回收线程 进行 垃圾回收  垃圾回收完之后 线程恢复正常运行


                     如果是老年代达到了一定的阈值就会引发 Full GC  把没有被引用的做一个标记

                     然后整理存存活对象  把死去的对象做一个垃圾回收这时是会STW暂停所有线程 等垃圾回收完了  线程就恢复正常运行

                     老年代采用的是标记整理或者是标记清除

       吞吐量优先 (Parellel GC 垃圾回收器)并行回收: 会STW( stop the word)

            jvm的参数:顾名思义

                -XX:+UseParallelGC (新生代)  -XX:+UseParallelOldGC (老年代) (这是个开关 开启任意一个就会自动的把另一个开启)

                -XX:+UseAdaotiveSizePolicy (用来动态的管理堆内存中 的 新生代和老年代 还有 伊甸园(Eden) 幸存区 (survivor) )

                -XX:+ParallelGCThreads=n ( 用来设置线程数量的)

                -XX:+GCTimeRatio  吞吐量的计算公式 :  吞吐量 = 用户线程 / (用户线程 + 垃圾回收时间)

   比如: 回收垃圾100分钟只有1分钟来回收垃圾

                -XX:+MaxGcpauseMillis=ms (每次回收的时间 默认200ms)

                吞吐量优先是一个多线程(多个人一起工作)

                吞吐量优先是jdk 1.8 引入进来的 并且还是jdk8默认的垃圾回收器

          吞吐量优先的基本流程:

3118d5f248e84ca4a01c89cce12cb23d.png

                      首先内存不足时就会 引发垃圾回收 Minor GC

                      把一些没有被GC Roots 所引用的对象标记起来,然后就复制到 幸存区中

                      回收时会发生STW暂停所有线程等垃圾回收完毕再恢复运行

                      如果是老年代垃圾回收不足时就会引发Full GC 进行垃圾回收

                      突发STW暂停所有线程 等垃圾回收完毕恢复其他线程
                 

        响应时间优先 (CMS GC垃圾回收器)并发回收:

        响应时间优先是一个多线程(多个人一起工作)

        只要是并发 都不会stop the  word(STW)暂停其他线程

        响应时间优先的执行流程:

88aba4b2fd9d4f7fab8a3a030e5ec5c1.jpeg

               当老年代的内存不足时 会进入安全点 然后进行初始标记(会STW)暂停其他线程 ,

              初始标记 完了之后就进行并发标记(因为是并发标记  用户线程和垃圾回收线程并发执行)不会干扰其他用户线程 过了这并发标记之后

              就会进行重新标记(会STW)在做重新标记之前会把新生代的 垃圾做一次垃圾回收  免得全部都重新标记一下就效率就低了很多

              最后做一个并发清理 不会干扰到其他用户线程 然后进入重置线程的候就会先清除掉之前标记的对象,然后再来次重置线程就一直重复一直重复

注意的是:如果老年代的回收垃圾不足时 做一个并发标记   但是 标记失败了那么就会退回掉串行(serial) 之后就采用full GC 来回收垃圾就会STW的时间可能会比较长,为什么?因为是多个线程。

        G1 GC ( garbage  first  垃圾回收器 )区域分代:每个区域都划分为相同大的区域 也是一个并发的一个垃圾回收器

            分别为3个部分 young Collection -->> young Collection + Concurrent Mark -->> Mined

Collection 然后又回来 young Collection

       可以看到这三个部分是循环的

     G1 是jdk9默认的垃圾回收器 ,将堆内存划分为多个相同的大小的区域(region)

               而这些区域包含新生代(伊甸园 Eden 幸存区 survivor)老年代

         young Collection (对新生代的一个垃圾回收):

                 首先新生代的内存达到了一定的阈值,引发了 minor GC(新生代) 回收垃圾

                 把没有被GC Roots关联的对象做个标记

                 然后把存活的对象复制到幸存区中 把标记的对象回收掉

                 如果又内存不足了,新生代就又会第二次的 minor GC(新生代) 回收垃圾

                 把没有被引用(GC Roots)的对象做一个标记 

      注意:然后把存活的对象放到另一个幸存区中 并且寿命加1 (因为G1 把堆内存分为多个相同

大小的区域)然后回收掉标记的对象,如果新创建出来的对象还是放到新生代中

   如果寿命达到要求就会晋级到老年代中  。

        young Collection + ComCurrent Mark (对新生代的一个垃圾回收并且并发标记)

               -XX:InitialtingHeapOccupancyPercent=percent(默认为45)你应该知道

         该参数是当内存达到一定的阈值比如说默认是45,到了45就会直接进行full gc 会释放所有堆的内存

       内存不足时 会young Collection 标记伊甸园 (Eden)中没有被根对象所引用的会被当成垃圾回收,

       然后把存活的复制到幸存区 如果幸存区内存不足时也是一样的 会标记 然后 复制到另一个幸存区中  。

       young Collection 跨代引用

                从GR Root 对象中找 对象  判断老年代中的对象是否可达性,那不是这种要扫描整个老年代的内存中的对象是否是可达性的?      

                解决方案:

                        使用 Remembered set 就是用来避免扫描全局的对象。

                        Remembered set 就是有哪些对象被外部引用了的

                然后垃圾回收就会先去remembered set 是否被引用了  不会扫描全局堆内存 大大的提高了效率

        Mixed Collection 混合回收 :

                会对新生代(伊甸园 和 幸存区) 和老年代进行混合回收(就是对堆内存全部都回收一次)

                有两个角色:拷贝存活(拷贝存活的对象)、最终标记(标记最大的对象)

               回收老年代的内存时会将最大的对象回收掉,就是回收时会从最大对象开始回收,然后复制到新的老年代中  意思就是拷贝。

        十分注意的一件事 : 我只是写写保存下来 ,只是个初学者 ,

                都是随便乱写的哈,别喷哈 如果有什么写的不对的欢迎评论哈 如果有什么写的不对的欢迎到评论区留言 谢谢!

       

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值