初步认识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公社阅读原文】。感谢您的支持!

您可能感兴趣的

去哪儿系统高可用之法:搭建故障演练平台... 作者介绍 王鹏, 2017年加入去哪儿机票事业部,主要从事后端研发工作,目前在机票事业部负责行程单和故障演练平台以及公共服务ES、数据同步中间件等相关的研发工作。 去哪儿网2005年成立至今,随着系统规模的逐步扩大,已经有成百上千个应用系统,这些系统之间的耦合度和链路的复杂度不断加强,对...
用 Google 表格做个虚拟机 简评:谁能有原作者会玩?活脱脱把一个表格处理工具当作像微处理器来运行,感觉以后「微型计算机原理」都可以用这个做实验了。 我最近注意到,Google Docs 有一个叫 Apps Script 的全功能脚本系统,它可以让你使用JavaScript 做一些非常有用的事情: ...
Redis未授权访问漏洞的重现与利用 *本文原创作者:flurry,本文属FreeBuf原创奖励计划,未经许可禁止转载 前言: 最近配置openvas的时候安装了redis,听说曾经曝出过一个未授权访问漏洞,便找了一下相关资料想自己动手复现一下漏洞的利用过程,当然所有的攻击性操作都是在虚拟机上完成的,本文所有的操作是在Fed...
JVM如何处理方法调用 所有方法在Class文件都是一个常量池中的符号引用,类加载的解析阶段会将其转换成直接引用,这种解析的前提是:要保证这个方法在运行期是不可变的。这类方法的调用称为解析。 jvm提供了5条方法调用字节码指令: invokestatic:调用静态方法 invokespecial:...
2-JVM-内存模型 私有 线程 程序计数器PC(native时为undefined) 虚拟机栈 本地方法栈(结构取决于语言) 虚拟机栈 栈帧(分配后无法改变大小) ...