通过对GC 理论部分的学习已经对JVM GC 有了比较全面的了解,已经了解了GC 的几种类型已经工作流程。本节主要从实践角度分门别类的了解GC 的各方面信息。
在HotSpot JVM 中有三种概念,分别代表了不同代中发生的GC 动作。
Minor GC:指发生在新生代的垃圾收集动作,由于新生代中对象生命周期较短,更新速度迅速,所以Minor GC 也会比较频繁,Minor GC 的回收速度也比较快。Minor GC 通常使用copying 算法,此算法一般为最有效的。
Major GC:指发生在老年代或永久代的垃圾收集动作,出现了Major GC,通常会伴随至少一次的 Minor GC(但有的收集策略会只有Major GC)。MajorGC 的速度一般会比比较慢。
Full GC:指对堆内存整体进行垃圾收集(包含新生代,老年代,永久代),有时可以理解为仅是Major GC,又可以理解为Major GC + Minor GC,因为概念理解上的差异我们理解Full GC 为清理所有内存即可。
下面是内存及GC 的相关参数:
内存相关设置(32位系统Heap 最大支持2GB,64位以上无限制)
-Xms:初始堆(Heap)大小,默认3670k。当空闲堆内存小于40%时,JVM 就会增大堆内存直到-Xmx 所设置的最大值,可以通过-XX:MinHeapFreeRatio=n 设置其比例。
-Xmx:最大堆(Heap)大小,默认64m。当空闲堆内存大于70%时,JVM 会减少堆内存直到-Xms 所设置的最小值,可以通过-XX:MaxHeapFreeRatio=n 设置其比例。
-Xmn:新生代大小,增大新生代后会相应减小老年代大小。此值对系统性能影响较大,Java 官方推荐配置为整个堆大小的3/8。
-Xss:设置每个线程栈的大小。Java1.5 以后每个线程栈默认大小为1M,之前每个线程栈默认大小为256K。可以根据应用的线程所需内存大小进行调整。一般情况下默认值已经能满足绝大部分情景的应用,如果想更进一步优化则需要非常细致的测试。在相同物理内存下,减小这个值能生成更多的线程,进程中可容纳线程数量与很多因素有关,感兴趣的可以详细了解下,据说可以达到6500个以上。
-XX:MinHeapFreeRatio=40:如果发现空闲堆内存占到整个预估上限值的40%,则增大上限值。
-XX:MaxHeapFreeRatio=70:如果发现空闲堆内存占到整个预估上限值的70%,则收缩预估上限值。
-XX:NewRatio=2:设置年轻代和老年代的比值。例如:n=3,则表示年轻代与老年代比值为1:3,年轻代占整个年轻代与老年代之和的1/4。
-XX:SurvivorRatio=8:Eden 与Survivor 的占用比例。例如8表示,一个survivor 区占用 1/8 的Eden 内存,即1/10的新生代内存,此处需注意年轻代有2个survivor 区,所以比例为1:10。
-XX:TargetSurvivorRatio=50:实际使用的survivor 空间大小占比。默认是47%,最高90%。
-XX:MaxPermSize=64m:设置持久代(即方法区)占整个堆内存的最大值。
-XX:MaxTenuringThreshold=0:设置对象最大年龄。即对象在在Eden 与Survivor 区之间被复制的次数,每被复制一次就增加1岁,默认值为15。如果设置为0的话,则Eden 中对象不经过Survivor 区直接进入老年代。
收集器设置
-XX:-DisableExplicitGC:禁止在运行期显式地调用System.gc(),开启该选项后,GC 的触发时机将由Garbage Collector 全权掌控,默认:关闭。
-XX:+ScavengeBeforeFullGC:在Full GC前触发一次Minor GC,默认:启用。
-XX:+UseGCOverheadLimit:限制GC的运行时间。如果GC耗时过长,就抛OutOfMemoryError。
-XX:ParallelGCThreads=n:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
-XX:+UseTLAB:启用线程本地缓存区(Thread Local)。
-XX:+UseSerialGC:使用串行收集器。
-XX:+UseParallelGC:使用并行收集器。
-XX:+UseParallelOldGC:使用并行压缩收集器。
-XX:+UseConcMarkSweepGC:使用CMS 收集器。
G1收集器设置
-XX:+UseG1GC:使用G1收集器。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间,这是一个理想目标,JVM 将尽最大努力来实现它。
GC 日志设置
-XX:+PrintGC:开启GC日志打印。
-XX:+PrintGCDetails:打印GC回收的详细信息。
-XX:+PrintGCTimeStamps:打印GC停顿耗时。
-Xloggc:<filename>:输出GC 详细日志信息至指定文件。
-XX:+UseGCLogFileRotation:开启GC 日志文件切分功能,前置选项 -Xloggc。
-XX:NumberOfGClogFiles=1:设置切分GC 日志文件数量,文件命名格式:.0, .1, ..., .n-1。
-XX:GCLogFileSize=8K:GC日志文件切分大小。
参数的意义基本已经了解,下面就讲一讲如何使我们的程序运行的更快,更稳定。
1.内存相关设置
(1)首先是操作系统的选择,在32位操作系统下JVM 只支持最大2GB Heap 大小,所以这大大的局限了程序的运行性能。然而在64位操作系统下则没有任何限制,所以推荐使用64位操作系统。
(2)然后是硬件方面,可以根据经济情况相应增加CPU 数量及物理内存大小,这样利用并行收集器可以带来很高的垃圾清理效率。
(3)Heap 相关参数设置,大型的应用系统常常会被两个问题困扰:一个是启动缓慢,因为初始Heap 非常小,必须由很多major 收集器来调整内存大小;另一个更加严重的问题就是默认的Heap 最大值对于应用程序来说“太可怜了”。根据以下经验法则(即拇指规则,指根据经验大多数情况下成立,但不保证绝对):
1)给于虚拟机更大的内存设置,往往默认的64mb 对于现代系统来说太小了。
2)将-Xms 与-Xmx 设置为相同值,这样做的好处是GC 后不用再频繁的根据内存使用情况去动态修改Heap 内存大小了,而且只有当内存使用达到-Xmx 设置的最大值时才会触发垃圾收集,这给GC 及系统减轻了负担。
3)设置过堆大小之后,可以根据程序创建对象的频率来调整新生代的内存大小,如果程序中创建新对象的频率比较搞可以适当调大新生代,但不要盲目调整,因为新生代的大小对JVM 及系统性能影响较大,Java 官方推荐配置为整个堆大小的3/8,此值可以通过非标准参数-Xmn 直接调整大小或不稳定参数-XX:NewRatio=2 间接调整新生代与老年代的大小比值。
4)线程中栈的大小调整也是如此,需要比较谨慎及细致的测试之后修改。
2.GC 收集器的选择
在HotSpot JVM 中有大致5类收集器:串行收集器,并行收集器,并行压缩收集器,CMS 收集器,G1收集器。其中并行被并行压缩收集器所替代,CMS 收集器被G1收集器所替代,所以可供选择的只剩下三种。
(1)串行收集器(Serial Collector)
在同一时间只会执行一件垃圾清理任务,非常适用于单线程,单CPU 架构的程序,串行收集器的开销也比较小,在老年代中使用mark-sweep-compact(标记—扫描-压缩)算法, 对于堆内存不是很大的程序比较适用。
串行收集器适用场景:客户端程序(-client)和单线程比较小的应用。可以声明-XX:+UseSerialGC 选项使用串行收集器。
(2)并行压缩收集器(Parallel Compacting Collector)
并行压缩收集器是在J2SE1.5后引入,与并行收集器(并行收集器又被称作吞吐量收集器)最大的不同是对老年代的回收使用了不同的算法,并行压缩收集器最终会取代并行收集器。并行压缩收集器最大的优点就是在消耗部分硬件性能及多CPU 支持下可以做到更短的stop-the-world 暂停,使回收效率更高从而增加了程序的吞吐量。
并行压缩收集器适用场景:程序稳定长期运行,希望任何时候我们的程序都能得到响应,即使程序执行速度缓慢,例如一些后台程序。硬件水平较高,例如多CPU,多物理内存的服务器可以选择并行压缩收集器。可以声明-XX:+UseParallelOldGC 选项使用并行压缩收集器。
(3)CMS 收集器(Concurrent Mark-Sweep (CMS) Collector)
在很多应用中,更加注重快速的相应时间而不是吞吐量。新生代的垃圾回收通常不会造成长时间的应用程序中断,但是,对于老年代,特别是当Heap 已使用量比较大的时候会导致长时间的程序中断(虽然这种情况不常发生)。Hotspot JVM 引入CMS 的目的就是为了解决这个问题。
CMS 收集器适用场景(G1同理):对于老年代使用率比较高的应用程序适合CMS 收集器,对停顿时间有较严格要求的程序也比较适合使用CMS 收集器。所以CMS 收集器多用于应用服务器程序上,例如web系统等。这类系统的共同特点就是响应时间一般较短,否则容易造成用户体验差的评价。可以声明-xx:+UseConcMarkSweepGC 选项使用CMS。如果你还想让CMS 运行与增量模式下,则可声明–XX:+CMSIncrementalMode 选项启用增量模式。增量模式指的是把收集器的工作分成多个时间块,然后在两次新生代的回收期间加以运行,这种方式可以更进一步减少暂停的时间。
3.GC 日志的使用
然后来看一段非常简单的代码:
public class GCTest { public static void main(String[] args){ for (;;) { System.gc(); } } }
Java 代码编译后,在控制台输入如下命令来运行此程序:
java -server -verbose:gc GCTest 或 java -server -XX:+PrintGC GCTest
[GC 160K->160K(125312K), 0.0004590 secs]
[Full GC 160K->160K(125312K), 0.0063689 secs]
.....
从运行结果我们可以看到GC 的执行情况,-verbose:gc 与-XX:+PrintGC 两个参数的作用相同,都是打印GC 基本信息,但基本信息中可参考的内容基本没有。
需要更加详细的GC 信息输出,可以使用-XX:+PrintGCDetails 参数,来打印GC 详情信息:
java -server -XX:+PrintGCDetails Contacts
[Full GC (System) [PSYoungGen: 0K->0K(38144K)] [PSOldGen: 160K->160K(87168K)] 160K->160K(125312K) [PSPermGen: 2937K->2937K(21248K)], 0.0055359 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[GC [PSYoungGen: 654K->32K(38144K)] 814K->192K(125312K), 0.0002939 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
.....
(执行class 文件)
java [-options] -jar jarfile [args...]
(执行jar 文件)
除了将GC 信息直接打印到控制台外更常用的做法是以文件的形式存储日志信息,利用-Xloggc:<file> 来实现:
java -server -XX:+PrintGCDetails -Xloggc:d:\gc.log GCTest
GC 打印的日志信息有固定的格式,可以将每条日志拆分成几部分来分析。
Minor GC:
Full GC:
日志中已经包含了上面所说的几种不同内存中的GC 执行情况,可以很方便的了解那部分内存使用出现了问题,这样就可以集中解决出现问题的部分。
4.其他(会不断补充)
(1)避免使用大对象
所谓大对象就是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串及数组。大对象对虚拟机的内存分配来说就是一个"bad message",经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的连续空间来“安置”它们。
这样的大对象如果只是使用1次的话,那么可想而知会对内存造成多么大的浪费,而且为了“挽回”这种过失,GC 会不断的去清理这些大对象所占用的内存空间,进而大致了程序运行的缓慢,所以在编码阶段就应该去重点注意这方面的问题不要为了开发方便而将很多“无关”的东西塞到一个对象中。
相关推荐
本文档是一份详细探讨Java垃圾回收机制及其影响的白皮书,标题为《Understanding Java Garbage Collection v4.pdf》,旨在帮助Java开发者和架构师理解垃圾回收器的应用行为、特性和机制,并在Java平台上选择和调整...
《Plumbr Handbook Java Garbage Collection》是一本专注于Java垃圾收集机制的详细指南,旨在帮助读者理解并优化Java应用程序中的内存管理。本手册由Plumbr的联合创始人撰写,Plumbr是一家专注于JVM性能监控的产品...
根据提供的文件信息,以下是对《The Java Garbage Collection Mini Book》这本书的主要知识点梳理和说明: 标题说明:《The Java Garbage Collection Mini Book》是一本专注于Java垃圾回收机制的小册子,由InfoQ...
Java垃圾回收(Garbage Collection,简称GC)是Java运行时环境(JRE)中的一个关键特性,它自动管理对象的生命周期,释放不再使用的对象所占用的内存空间。在Java中,对象在不再被任何引用链可达时,即被视为垃圾,...
《垃圾收集手册》是关于自动内存管理的一本权威著作,主要探讨了计算机程序中的垃圾收集(Garbage Collection, GC)技术。垃圾收集是现代编程语言中一个至关重要的部分,它负责自动识别并释放不再使用的内存空间,...
健壮性与高性能:Java通过垃圾回收机制确保内存的有效管理,同时也能通过JIT编译器优化来提升运行时性能。 标准库丰富:Java拥有庞大的类库,如Java SE(Java Standard Edition)包含基础API,用于开发通用应用...
垃圾回收(Garbage Collection,简称GC)是Java语言的一个重要特性,它自动化地管理程序中的内存分配与释放,避免了传统C++等语言中的内存泄漏问题。本文将围绕Java垃圾回收这一主题,展开一系列关键知识点的详细解析...
### Java垃圾回收经典手册知识点概览 #### 一、引言 《Plumbr Java垃圾回收手册》(2015年英文版)是一本详细介绍了Java虚拟机(JVM)中垃圾回收机制的经典指南。该手册由Nikita Salnikov-Tarnovski和Gleb Smirnov...
Java垃圾回收是Java平台应用程序行为的一个重要组成部分,它负责回收Java虚拟机(JVM)堆内存中不再使用的对象,以释放内存空间。垃圾回收机制可以显著影响应用程序的性能、吞吐量、可伸缩性和可靠性。本文将详细...
一、IBM Garbage Collection(GC) IBM GC是IBM J9 JVM中的内存管理机制,它的主要任务是自动释放不再使用的对象所占用的内存空间。GC的工作涉及到对象的分配、存活判断、内存回收以及内存区域的调整等多个环节。...
"03 GarbageCollection.zip"这个压缩包文件,其标题暗示了我们将探讨的是垃圾收集(Garbage Collection, GC)这一核心概念,特别是在数据结构和算法的学习中,理解GC的工作原理对于优化程序性能至关重要。...
4. Major GC:在Java垃圾回收过程中实例生命周期的最后一个阶段。Major GC在垃圾回收过程中扫描属于Old Generation部分的堆内存。 垃圾回收器类型 ------------- Java提供了四种可用的垃圾回收器类型: 1. Serial...
总之,Java VisualVM是一个强大的工具,它使得Java开发者能够有效地监控和分析垃圾回收机制,从而优化应用性能,解决内存相关问题。通过熟练掌握VisualVM的使用,开发者能够更好地理解和控制Java应用的内存管理,...
垃圾收集(Garbage Collection, GC)是Java虚拟机的一项重要功能,它负责自动管理内存,识别并回收不再使用的对象,以避免内存泄漏。HotSpot虚拟机提供了多种不同的垃圾收集器,每种都有其特定的性能特性和适用场景...
垃圾收集(Garbage Collection, GC)是Java编程语言的一个关键特性,它自动管理程序的内存空间,回收不再使用的对象,防止内存泄漏。GC的工作原理包括标记、清除、压缩等阶段,这些过程会影响应用的运行效率,尤其是...
在IT行业中,垃圾回收(Garbage Collection,简称GC)是一项重要的技术,特别是在使用像Java、Python、Ruby等高级编程语言时。垃圾回收是自动管理内存的一种机制,它负责监测和释放不再使用的内存空间,以防止内存...
垃圾收集(Garbage Collection, GC)是这一过程的核心,它负责识别并回收不再使用的内存空间。本篇文章将深入探讨几种常见的垃圾收集算法,以及它们在Java J2EE、C#、ASP.NET以及JVM中的应用。 1. **标记-清除...