初步认识Java虚拟机中的垃圾收集器

综合编程 2018-05-28

前言

Java虚拟机的垃圾收集器是虚拟机内存的清道夫,它的存在让Java开发人员能将更多精力投入到业务研发上。了解垃圾收集器,并利用好这个工具,能更好的保障服务稳定性。这篇文章通过分析Java虚拟机内存模型,介绍垃圾收集器常用算法和收集器类别,使得垃圾收集器的配置和使用变得不再遥不可及。

Java虚拟机内存模型

Java虚拟机内存可以划分为:虚拟机栈、本地方法栈、JAVA堆内存、方法区(包含运行时常量池)、程序计数器、直接内存。

虚拟机栈

虚拟机栈是线程私有的,生命周期跟线程相同。也就是说一个线程被创建后,虚拟机为其分配了一个独立的栈帧来存储线程的局部变量、操作数、动态链接、方法出口等信息,当线程结束后,该栈帧也会被回收清理。

本地方法栈

本地方法栈是虚拟机的native方法执行期间使用的一个栈帧。

Java堆内存

堆内存是被所有线程共享的一块区域,用来存放对象实例和数组,属于内存中最大的一块区域,也是垃圾收集的主要区域。从垃圾收集的角度看,堆内存经常分为新生代和老年代。

方法区

方法区也是被所有线程共享的一块区域,用来存储被虚拟机加载的类信息、常量、静态变量、JIT编译后代码等数据。也可以成为永久代。

程序计数器

程序计数器是线程私有的,作为当前线程所执行的字节码的行号指示器,每个线程有一个程序计数器,用于记录CPU切换线程时记录当前线程的执行位置,以便下次继续从当前位置往下执行。

直接内存

这块不属于JAVA虚拟机内存,但使用频繁,也可称之为“堆外内存”

Java虚拟机垃圾收集器

根据上述对JAVA虚拟机内存区域模型的介绍,我们知道JAVA程序中的对象实例都存储在JAVA堆内存中,因此垃圾收集主要也是针对堆内存进行。为了更好的管理JAVA对象实例,并结合对象实例的生存时间长短,JAVA虚拟机将堆内存分为新生代和老年代,分别存储刚创建不久的对象和存活较长时间的对象实例,并采用分代收集的策略分别回收新生代和老年代的内存。

内存分配与回收策略

  • 1、 分代收集思路。根据JAVA对象的生存周期特点,虚拟机将堆内存分为新生代和老年代,并分别采用新生代和老年代的垃圾回收策略。
  • 2、 新生代细分为Eden区和两个Survivor区(即From区和To区)。大多数新生对象创建频繁,且存活时间短,为了提高新生代区域垃圾收集效率,新创建的对象存放在Eden区,当Eden区快满的时候,虚拟机对其触发一次Minor GC,将新生代存活对象移动到From区,原来From区的对象根据存活年龄决定放到To区还是老年代,然后清空Eden区和From区,接着将To区对象全部移到From区。
  • 3、 大对象直接进入老年代,可以配置新生代对象的最大值,对象超过这个值就直接进入老年代。
  • 4、 发起Minor GC前,会先判断老年代最大可用连续空间是否大于新生代对象占用的空间,如果小于或不允许冒险,则触发一次Full GC。

垃圾收集算法(3种基本算法)

  • 1、 复制算法。针对于新生代的垃圾收集算法。当新生代Eden区快满的时候,将Eden区对象复制到From区,将From区对象根据存活年龄决定复制到To区还是到老年代,然后清除Eden区和From区,接着将To区对象复制到From区。
  • 2、 标记-清除算法。垃圾收集算法标记出需要回收的对象,标记完成后直接统一回收。垃圾收集器使用可达性分析来判断哪些对象是否存活,通过设置一系列GC Roots节点(包括栈、方法区中的静态属性和常量所引用的对象,以及本地方法栈中引用的对象),从这类节点往下搜索,当对象不在GC Root节点的引用链上时,说明对象不可达,可以被回收。
  • 3、 标记-整理算法。垃圾收集算法标记出需要回收的对象,标记完成后将存活对象往内存的一端移动,然后直接清理掉端边界以外的内存。

常用垃圾收集器

由于虚拟机中的垃圾收集是分代收集的,新生代和老年代的垃圾收集策略不太一样,所以一般是使用针对新生代和老年代的垃圾收集器组合。

  • 1、 Serial GC。新生代收集器,采用复制算法,用于Client客户端新生代垃圾收集,针对内存占用较少的应用进行垃圾收集。
  • 2、 Serial Old GC。老年代收集器,采用标记-整理算法,用于Client客户端老年代垃圾收集,针对内存占用较少的应用进行垃圾收集。
  • 3、 Parallel Scavenge GC。新生代收集器,采用复制算法,并行收集新生代内存垃圾,可以设置垃圾收集器的吞吐量,还可以设置自动适配调节吞吐量。
  • 4、 Parallel New GC。新生代收集器,采用复制算法,并行收集新生代内存垃圾。
  • 5、 Parallel Old GC。老年代收集器,采用标记-整理算法,并行收集老年代内存垃圾。
  • 6、 CMS GC。老年代收集器,采用标记-清除算法,并行收集老年代内存垃圾,不整理内存。由于在执行垃圾收集期间不中断业务线程,所以容易产出“浮动垃圾”,导致Full GC。可以通过设置参数来触发内存整理任务。
  • 7、 G1 GC。不再将堆内存区分新生代和老年代,而是将堆内存看作若干个均分小区域,并对最空闲的内存区域进行标记和回收。适用于大内存的应用。

配置垃圾收集机器参数

  • 1、UseSerialGC:虚拟机允许在Client模式下的默认值,打开此配置后,虚拟机使用Serial GC + Serial Old GC 的收集器组合进行内存回收。
  • 2、UseParNewGc:使用ParNew + Serial Old 的收集器组合进行内存回收。
  • 3、UseConcMarkSweepGC:使用ParNew + CMS + Serial Old GC的收集器组合进行内存回收。
  • 4、UseParallelGC:虚拟机允许在Server模式下的默认值,使用Parallel Scavenge + Serial Old 的收集器组合进行内存回收。
  • 5、UseParallelOldGC: 使用Parallel Scavenge + Parallel Old GC的收集器组合进行内存回收。
  • 6、SuriviorRatio:新生代中Eden区域与Surivior区域的容量比值,默认是8:1。
  • 7、PretenureSizeThreshold:设置这个值后,大于这个值的对象直接进入老年代。
  • 8、MaxtenuringThreshold:对象年龄超过这个值时进入老年代。
  • 9、ParallelGCThreads:设置并行GC时进行内存回收的线程数。
  • 10、UseAdaptiveSizePolicy:动态调整堆内存中各个区域的大小和进入老年代的对象年龄。
  • 11、HandlerPromotionFailure:是否允许分配担保失败。
  • 12、GCTimeRatio:仅在Parallel ScaVenge收集器时生效,设置GC时间占总运行时间的比率,默认为1%。
  • 13、MaxGCPauseMills:仅在Parallel ScaVenge收集器时生效,设置GC的最大停顿时间。
  • 14、CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发垃圾收集,默认68%,在设置CMS收集器时生效。
  • 15、UseCMSCompactAtFullCollection:在设置CMS收集器时生效,设置CMS收集器在完成垃圾收集后是否进行一次碎片整理。
  • 16、CMSFullGCsBeforeCompaction:仅在使用CMS时生效,设置CMS收集器在进行若干次收集后再启动一次内存碎片整理。

本文永久更新链接地址: https://www.linuxidc.com/Linux/2018-05/152588.htm

Linux公社

责编内容by:Linux公社 (源链)。感谢您的支持!

您可能感兴趣的

响应式 Web 应用(二) 响应式编程是一种基于数据流以及传播数据变化的编程范例。例如,考虑表 1.1 中所表示的电子表格。 单元格 C1 以如下的方式来定义: C1 = A1 * B1 如果我们在电子表格中运行上述例子,一旦 A1 或者 B1 的值发生改变,那么 C1 的结果将相应地作出改变。...
用户须知的容器生态系统中顶级供应商... 在过去两年中,容器生态系统发生了爆炸式的增长,因为企业希望利用这个成熟的容器市场来实现增长。根据451 Research发布的一份报告预测,容器生态系统将从去年的7.62亿美元增长到2020年的27亿美元。Forrester Research估计,31%的企业IT组织已经部署了容器。 本次列举出...
深入理解Java:String 一、Java内存模型 按照官方的说法:Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。 JVM主要管理两种类型内存:堆和非堆,堆内存(Heap Memory)是在 Java 虚拟机启动时创建,非堆内存(Non-heap Memory)是在JVM堆之外的内存...
深入理解Java并发之synchronized实现原理 【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/72828483 出自【zejian的博客】 关联文章: 深入理解Java类...
深入理解JVM(五)Class类的文件结构 1.Class文件的定义 Class文件时一组以8位字节为基础单位的二进制流,当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个*位字节进行存储。Class文件格式采用一种类似C语言结构体的伪结构来存储数据, 这种伪结构中只有两种数据类型:无符号数和表。 ...