码迷,mamicode.com
首页 > 其他好文 > 详细

JVM 垃圾回收

时间:2018-01-08 23:48:47      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:bag   strong   产生   reg   溢出   each   基本   自适应   blog   

JVM 垃圾回收

 

这篇文章尝试对当前主流的JVM垃圾回收机制进行简要介绍。

 

一 垃圾回收讨论的范围

JVM 的内存分为方法区,JVM栈,本地方法栈,堆,程序计数器等几个部分。

其中程序计数器,JVM栈,本地方法栈三部分的生命周期与线程相同,随着线程的回收这几部分内存其生命周期自然结束而得以回收。

而方法区用于存储静态变量、常量、类信息等数据,堆更是用于创建对象时在其上划分内存。随着程序的运行,这些数据何时不再有用,需要被回收便是垃圾回收所关注的问题。

二 垃圾回收的基本策略

垃圾回收所要解决的问题便是将内存中无用的对象进行回收,以便释放出内存空间用于后续程序运行分配空间的需要。这里的问题主要有:

  1. 对象何时会无用
  2. 如何回收更加高效

对象何时会无用?

换句话说便是如何判断对象不会再被任何程序使用。一种解决方案是所谓“引用计数法”,即当程序中每有一处引用该对象时,引用技术器+1,当每有一处引用失效时,对应-1,当一个对象的“引用计数器”归零时,便认为其可以被回收。这种方案看似行之有效,但一个潜在的问题便是循环引用,假设A对象持有B对象的一个引用,B对象同时持有A对象的一个引用,当程序中任何其他地方不再有指向这两个对象的引用时,A和B仍旧互相持有,这导致A和B将永远不能被回收,试想程序中出现多处类似的现象,将极易引发内存溢出。

主流的程序语言中,通常采用可达性分析(Reachability Analysis)来判断对象是否无用。可达性分析是指,从GC Roots开始进行搜索,如果一个对象没有任何GC Roots能够到达的话便认为该对象不再有用。对于上面所述的互相引用的情况,显然是从GCRoots不可达的。在Java中,可能的GC Roots对象包括:

JVM栈中引用的对象

方法区中静态属性引用的对象

方法区中常量引用的对象

本地方法栈中引用的对象

如何回收更加高效?

所谓高效的问题,可以理解为如何在对应用程序影响最小的情况下完成最垃圾回收。即垃圾回收应尽可能不影响程序的正常运行,同时能够对不再有用的对象进行高效的回收以为程序的后续运行提供足够的空间。

三 几种垃圾收集器

    1.1. Serial / Serial Old收集器

    顾名思义,这是一款单线程收集器。其在线程回收时,仅有一个线程,同时所有的用户线程均会被停止,即所谓Stop the world,显而易见,对于要求具有较高性能的服务器程序来说,这种情况是难以接受的。而对轻量的客户端程序来说,如果Stop the world仅仅是毫秒或者数十毫秒级别的,那么采用这种简单而高效的垃圾回收器也未尝不可。

    技术分享图片

 

     1.2. ParNew 收集器

    ParaNew收集器可视为Serial收集器的多线程版本,是一款新生代垃圾收集器。由于Parallel Scavenge收集器不能配合CMS收集器使用,ParNew收集器便成为了配合CMS使用的新生代首选收集器,当使用CMS收集器时,ParNew收集器是默认的新生代收集器。也可通过-XX:+UseParNewGC 强制指定使用该收集器。

    技术分享图片

 

    1.3. Prarallel Scavenge收集器

    此收集器也是一款新生代多线程收集器。与ParNew收集器主要不同的是,该收集器主要关注吞吐量这个参数。

    吞吐量=time-of-user-program/(time-of-user-program + time-of-GC)

    吞吐量越高代表系统对CPU的利用率越高,能够将更多的时间投入到实际的计算中,这适合后台需要大量计算而交互较少的系统。

    该收集器提供-XX:MaxGCPauseMillis和-XX:GCTimeRatio两个参数用于控制吞吐量参数。吞吐量=1/(1+GCTimeRatio)。还提供了-XX:+UseAdaptiveSizePolicy用来开启自适应调整各内存分区大小

    1.4. Parallel Old 收集器

    Parallel Old收集器时Parallel Scavenge收集器的老年代版本,在关注吞吐量有限的应用场景中可以结合Parallel Scavenge使用

    1.5. CMS(Concurrent Mark Sweep)收集器

    该收集器以或多最短的停顿时间为目标,采用标记-清除算法。回收过程可以分为四步:

      a. 初始标记 initial mark

      标记GC Roots能够直接关联到达对象,速度很快,需要Stop the world

      b. 并发标记 concurrent mark

      进行GC Roots Tracing, 可与用户线程一同进行

      c. 重新标记 remark

      修正并发标记期间用户程序运行导致标记产生变动的部分,并行运行,需要stop the world

      d. 并发清除 concurrent seep

      与用户线程一并运行

    整个过程中,1和3需要stop the world,但所占用的时间短,而2和4占用的时间长但可以与用户线程一同进行,因此整体上对用户程序产生的停顿影响较小。

    技术分享图片

 

    1.6. G1(Garbage First) 收集器

    G1收集器可以独立完成新生代和老年代的垃圾回收,除了这种传统划分外,其将内存区域划分为若干个独立的Region。从整体上看G1采用标记-整理算法,而对每个Region则采用复制算法,可以有效避免产生大量内存碎片导致频繁GC。此外,G1还会评估每次回收时各Region回收的价值大小,优先回收价值高的Region。主要分为以下几步

    1.   初始标记 initial mark
    2.   并发标记 concurrent mark
    3.   最终标记 final mark
    4.   筛选回收 live data counting and evacuation

    其他步骤与CMS类似,而第四步主要评估各Region回收价值的大小和成本,按照用户期望的代价进行回收。

    技术分享图片

 

 

 

JVM 垃圾回收

标签:bag   strong   产生   reg   溢出   each   基本   自适应   blog   

原文地址:https://www.cnblogs.com/luojiahu/p/8245488.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!