转载:http://www.cnblogs.com/maybo/p/7786229.html
本章通过阅读JVM垃圾搜集指南文档,整理虚拟机主要配置以及,理解不同的垃圾搜集器。
垃圾搜集算法
- 引用计数算法
- 根搜索算法
- 标记-清除算法
- 复制算法
- 标记-整理算法
- 分代收集算法
搜集算法网上有很多介绍这里不在进行整理。
解决问题:
对象的回收是一个繁重负载的工作,自动垃圾回收可以使开发人员从繁重的垃圾回收中解放出来,而且,也避免由于垃圾回收带来的问题。
针对的重点:
垃圾回收是会造成停顿现象,和碎片现象。所以不同的搜集器主要在降低系统的停顿时间以及避免产生内存碎片,以此提高程序的运行性能。
两个主要指标:
响应时间和吞吐量。响应时间和停顿时间有关,停顿时间越长响应的时间也越长,吞吐量是垃圾回收时间消耗外和运行总时间的比。降低垃圾回收的时间消耗有助于提高吞吐量。
垃圾回收机制选择依据:
个人觉得主要和两方面有关,第一是项目是实时性要求高的还是对吞吐量要求高的,第二就是系统资源也就是cpu和内存资源。如: 单核cpu 串形垃圾回收器是首选,高吞吐量的应用在多核下并行搜集器是首选,对于实时性要求高的CMS是首选但是需要注意到老年代碎片问题,所以还要考虑全压缩。当然,值得一提的是在java1.9已经抛弃了CMS,替代品是G1这种分区域的垃圾回收器,G1在吞吐量和实时性的有很好的体现,更适合与多核,高内存的系统。
主要配置整理:
以下是有关服务器应用程序的堆大小的一般准则:
-
除非您遇到暂停问题,否则请尝试尽可能多地向虚拟机授予内存。默认大小通常太小。
-
设置
-Xms
和-Xmx
相同的值通过从虚拟机中删除最重要的尺寸决定来提高可预测性。但是,如果您做出了糟糕的选择,虚拟机将无法弥补。 -
通常,增加处理器的数量会增加内存,因为可以并行分配。
以下是服务器应用程序的一般准则:
-
首先决定您可以负担得起的虚拟机的最大堆大小。然后,针对年轻一代的尺寸绘制您的表现指标,以找到最佳的设置。
-
请注意,最大堆大小应该始终小于机器上安装的内存量,以避免页面过多和抖动。
-
-
如果总堆大小是固定的,那么增加年轻一代的规模就需要减少老一代的规模。保持足够大的旧一代以保存应用程序在任何给定时间使用的所有实时数据,加上一些松散空间(10%到20%或更多)。
-
根据之前对老一代的限制:
-
给年轻一代大量的记忆。
-
增加处理器的数量,增加年轻一代的规模,因为分配可以并行化
-
串行收集器
串行收集器使用单个线程执行所有垃圾收集工作,这使得它相对高效,因为线程之间没有通信开销。
它最适合单处理器机器,因为它不能利用多处理器硬件,尽管对于具有小数据集(高达大约100MB)的应用程序,它可能对多处理器很有用。串行收集器在某些硬件和操作系统配置中是默认选择的,或者可以通过选项显式启用-XX:+UseSerialGC
。
并行收集器
并行收集器也被称为吞吐量收集器,它是一个类似于串行收集器的世代收集器。串行收集器和并行收集器之间的主要区别在于并行收集器具有多个用于加速垃圾收集的线程。
并行收集器适用于在多处理器或多线程硬件上运行的中型到大型数据集的应用程序。您可以使用该-XX:+UseParallelGC
选项启用它。
并行压缩是一个使并行收集器能够并行执行主要搜集的功能。如果没有并行压缩,主要搜集使用单个线程执行的,这可能会严重限制可伸缩性。-XX:+UseParallelGC
指定了选项,则默认启用并行压缩。您可以通过使用该-XX:-UseParallelOldGC
选项来禁用它。
并行收集器相关参数
-XX:+UseParallelGC | Full GC采用parallel MSC (此项待验证) | 选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.(此项待验证) | |
-XX:+UseParNewGC | 设置年轻代为并行收集 | 可与CMS收集同时使用 JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值 | |
-XX:ParallelGCThreads | 并行收集器的线程数 | 此值最好配置与处理器数目相等 同样适用于CMS | |
-XX:+UseParallelOldGC | 年老代垃圾收集方式为并行收集(Parallel Compacting) | 这个是JAVA 6出现的参数选项 | |
-XX:MaxGCPauseMillis | 每次年轻代垃圾回收的最长时间(最大暂停时间) | 如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值. | |
-XX:+UseAdaptiveSizePolicy | 自动选择年轻代区大小和相应的Survivor区比例 | 设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开. | |
-XX:GCTimeRatio | 设置垃圾回收时间占程序运行时间的百分比 | 公式为1/(1+n) | |
-XX:+ScavengeBeforeFullGC | Full GC前调用YGC | true | Do young generation GC prior to a full GC. (Introduced in 1.4.1.) |
并行收集器默认堆大小
除非在命令行中指定了初始和最大堆大小,否则将根据机器上的内存量进行计算。默认最大堆大小是物理内存的四分之一,而初始堆大小是物理内存的1/64。分配给年轻一代的最大空间是总堆大小的三分之一。
并行收集器时间过长和OutOfMemory错误
OutOfMemoryError
如果垃圾收集(GC)花费了太多的时间,并行收集器会抛出一个。
如果超过98%的时间花在垃圾收集上,并且只有不到2%的堆被回收,那么OutOfMemoryError
就会抛出一个。此功能旨在防止应用程序长时间运行,而由于堆太小,进行很少或没有进度。如有必要,可以通过将选项添加-XX:-UseGCOverheadLimit
到命令行来禁用此功能。
并发收集器
并发标记扫描(CMS)收集器和垃圾首先(G1)垃圾收集器是两个最主要的并发收集器。大多数并发收集器执行一些昂贵的,实时的任务到应用程序。
-
G1垃圾收集器:这种服务器式收集器适用于具有大量内存的多处理器机器。它以高可用性满足垃圾收集暂停时间目标,同时实现高吞吐量。
在某些硬件和操作系统配置中,G1是默认选择的,或者可以显式启用
-XX:+UseG1GC
。 -
CMS收集器:此收集器适用于更短的垃圾收集暂停时间并且可以与垃圾收集共享处理器资源的应用程序。
使用该选项
-XX:+UseConcMarkSweepGC
启用CMS收集器
CMS收集器从JDK 9开始已弃用。
CMS相关参数
-XX:+UseConcMarkSweepGC | 使用CMS内存收集 | 测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代大小最好用-Xmn设置.??? | |
-XX:+AggressiveHeap | 试图是使用大量的物理内存 长时间大内存使用的优化,能检查计算资源(内存, 处理器数量) 至少需要256MB内存 大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提升) | ||
-XX:CMSFullGCsBeforeCompaction | 多少次后进行内存压缩 | 由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理. | |
-XX:+CMSParallelRemarkEnabled | 降低标记停顿 | ||
-XX+UseCMSCompactAtFullCollection | 在FULL GC的时候, 对年老代的压缩 | CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。 可能会影响性能,但是可以消除碎片 | |
-XX:+UseCMSInitiatingOccupancyOnly | 使用手动定义初始化定义开始CMS收集 | 禁止hostspot自行触发CMS GC | |
-XX:CMSInitiatingOccupancyFraction=70 | 使用cms作为垃圾回收 使用70%后开始CMS收集 | 92 | 为了保证不出现promotion failed(见下面介绍)错误,该值的设置需要满足以下公式CMSInitiatingOccupancyFraction计算公式 |
-XX:CMSInitiatingPermOccupancyFraction | 设置Perm Gen使用到达多少比率时触发 | 92 | |
-XX:+CMSIncrementalMode | 设置为增量模式 | 用于单CPU情况 | |
-XX:+CMSClassUnloadingEnabled |
GC时间过长和OutOfMemory错误
OutOfMemoryError
如果在垃圾收集中花费了太多时间,CMS收集器会抛出:如果超过98%的时间用于垃圾收集,并且少于2%的堆被恢复,那么的OutOfMemoryError 被抛出。
此功能旨在防止应用程序长时间运行,而由于堆太小,进行很少或没有进度。如有必要,可以通过将选项添加-XX:-UseGCOverheadLimit
到命令行来禁用此功能。
该策略与并行收集器中的策略相同,只是执行并发收集所花的时间不计入98%的时间限制。换句话说,只有在应用程序停止时执行的收集才会占用过多的GC时间。这样的集合通常是由于并发模式失败或明确的收集请求(例如,调用System.gc()
)。
并发标记扫描收集器暂停
CMS收集器在并发收集周期中暂停两次应用程序。第一个暂停是将从根(例如,应用程序线程堆栈和寄存器,静态对象等的对象引用)和堆中其他地方(例如年轻一代)可直接访问的对象标记为活动状态。
这第一个暂停被称为初始标记暂停。第二次暂停是在并发跟踪阶段结束时发现的,并且在CMS收集器完成对该对象的跟踪之后,由于对象中引用的应用程序线程的更新而找到由并发跟踪所遗漏的对象。这第二次暂停被称为暂停。
并行标记扫描收集器并发阶段
可达对象图的并发跟踪发生在初始标记暂停和标记暂停之间。
在此并发跟踪阶段期间,一个或多个并发垃圾回收器线程可能正在使用处理器资源,否则该应用程序可能已经可用该处理器资源。因此,即使应用程序线程未暂停,计算绑定的应用程序也可能在此阶段和其他并发阶段期间看到相应的应用程序吞吐量下降。标记暂停后,并发扫描阶段收集标识为不可访问的对象。收集周期完成后,CMS收集器将等待,几乎不消耗计算资源,直到下一个主要收集周期开始。
启用G1
Garbage-First垃圾收集器是默认收集器。
G1的一般建议
一般的建议是使用G1的默认设置,最终给它一个不同的暂停时间目标,并根据需要设置最大的Java堆大小-Xmx
。
G1的默认值与其他任何收藏家的平衡都不同。G1在默认配置下的目标既不是最大吞吐量也不是最低延迟,而是在高吞吐量时提供相对较小,统一的暂停。然而,G1增量式回收堆中的空间和暂停时间控制的机制会在应用程序线程和空间回收效率方面产生一些开销。
如果您更喜欢高吞吐量,那么通过使用-XX:MaxGCPauseMillis
或提供更大的堆来放松暂停时间目标。如果延迟是主要的要求,那么修改暂停时间目标。避免使用类似的选项限制了年轻一代的尺寸为特定值-Xmn
,-XX:NewRatio
和其他人因为年轻一代的尺寸是G1的主要手段,使其能够满足暂停时间。将年轻一代的规模设定为一个单一的值,并且实际上禁用暂停时间控制。需要执行任何其他操作。您可以通过-XX:+UseG1GC
在命令行上提供来显式启用它。
与其他收集器比较
这是G1和其他收集器之间主要区别的总结:
- 平行GC可以整体压缩和回收老一代的空间。G1逐渐将这个工作分配到多个更短的集合中。这显着缩短了暂停时间,但是可能会增加吞吐量。
- 与CMS类似,G1同时执行旧一代空间回收的一部分。但是,CMS不能对旧一代堆进行碎片整理,最终进入长满GC。
- G1可能比其他收集器显示更高的开销,由于其并发性而影响吞吐量。
由于它的工作原理,G1有一些独特的机制来提高垃圾收集效率:
- G1可以在任何收集过程中回收一些完全空白的大面积旧一代。这可以避免许多不必要的垃圾回收,从而不需要太多的努力就可以释放大量的空间。
- G1可以选择尝试同时在Java堆上重复删除重复的字符串。
从旧一代回收空的大型对象始终处于启用状态。您可以使用该选项禁用此功能-XX:-G1EagerReclaimHumongousObjects
。字符串重复数据删除默认是禁用的。您可以使用该选项启用它-XX:+G1EnableStringDeduplication
。
选项和默认值 | 描述 |
---|---|
| 最大暂停时间的目标。 |
| 最大暂停时间间隔的目标。默认情况下,G1没有设置任何目标,允许G1在极端情况下背对背执行垃圾回收。 |
| 垃圾收集期间用于并行工作的最大线程数暂停。这是通过以下方式运行VM的计算机的可用线程数得出的:如果进程可用的CPU线程数小于或等于8,则使用该线程。否则,添加五分之八的线程大于最后的线程数。 |
| 用于并发工作的最大线程数。默认情况下,该值 |
| 控制初始堆占用的默认值表示启用该值的适应性确定,并且对于前几个采集周期G1,将使用老一代的45%的占用作为标记开始阈值。 |
| 堆区大小的设置基于初始和最大堆大小。所以这个堆大约包含2048个堆区域。堆区的大小可以从1到32 MB不等,并且必须是2的幂。 |
| 年轻一代的总规模,这两个值之间的差异是当前使用的Java堆的百分比。 |
| 收集中允许的未回收空间以百分比形式设置候选人。如果收集集候选中的空闲空间低于G1,那么G1停止空间回收阶段。 |
| 在一些集合中的空间回收阶段的预期长度。 |
| 在这个空间回收阶段,没有收集到比这个百分比更高的活体对象占有率的老一代地区。 |
垃圾收集器简介
Garbage-First(G1)垃圾收集器是针对具有大量内存的多处理器机器的。它试图以高概率满足垃圾收集暂停时间的目标,同时实现高吞吐量而不需要配置。G1旨在利用当前的目标应用程序和环境,在延迟和吞吐量之间提供最佳平衡,其功能包括:
- 堆大小可达10 GB或更大,超过50%的Java堆被实时数据占用。
- 对象分配和促销的比率随着时间的推移会发生显着变化。
- 堆中的大量碎片。
- 可预测的暂停时间目标目标不超过几百毫秒,避免长时间的垃圾收集暂停。
G1取代了并发标记扫描(CMS)收集器。它也是默认的收集器。
G1收集器实现了高性能,并尝试通过以下几节中所述的几种方式来满足暂停时间目标。
选择一个收集器
除非您的应用程序具有相当严格的暂停时间要求,否则首先运行您的应用程序并允许VM选择一个收集器。
如有必要,调整堆大小以提高性能。如果性能仍然不能达到您的目标,那么请使用以下指南作为选择收集器的起点:
-
如果应用程序有一个小数据集(最多大约100 MB),则选择带有选项的串行收集器
-XX:+UseSerialGC
。 -
如果应用程序将在单个处理器上运行,并且没有暂停时间要求,则使用该选项选择串行收集器
-XX:+UseSerialGC
。 -
如果(a)峰值应用程序性能是第一优先级并且(b)没有暂停时间要求或暂停一秒或更长时间是可接受的,则让VM选择收集器或者选择并行收集器
-XX:+UseParallelGC
。 -
如果响应时间比整体吞吐量更重要,并且垃圾收集暂停必须保持短于大约一秒,那么使用
-XX:+UseG1GC
或选择并发收集器-XX:+UseConcMarkSweepGC
。
这些准则仅提供选择收集器的起点,因为性能取决于堆的大小,应用程序维护的实时数据量以及可用处理器的数量和速度。暂停时间对这些因素特别敏感,所以前面提到的1秒的阈值只是近似的。在许多堆大小和硬件组合上,并行收集器将经历一秒以上的停顿时间。相反,并发收集者在某些情况下可能不能保持短于一秒的暂停。
如果推荐的收集器不能达到预期的性能,则首先尝试调整堆和代的大小以达到预期的目标。如果性能仍然不足,请尝试使用其他收集器:使用并发收集器来减少暂停时间,并使用并行收集器来提高多处理器硬件的整体吞吐量。
辅助信息
-XX:+PrintGC | 输出形式: [GC 118250K->113543K(130112K), 0.0094143 secs] | ||
-XX:+PrintGCDetails | 输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] | ||
-XX:+PrintGCTimeStamps | |||
-XX:+PrintGC:PrintGCTimeStamps | 可与-XX:+PrintGC -XX:+PrintGCDetails混合使用 输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs] | ||
-XX:+PrintGCApplicationStoppedTime | 打印垃圾回收期间程序暂停的时间.可与上面混合使用 | 输出形式:Total time for which application threads were stopped: 0.0468229 seconds | |
-XX:+PrintGCApplicationConcurrentTime | 打印每次垃圾回收前,程序未中断的执行时间.可与上面混合使用 | 输出形式:Application time: 0.5291524 seconds | |
-XX:+PrintHeapAtGC | 打印GC前后的详细堆栈信息 | ||
-Xloggc:filename | 把相关日志信息记录到文件以便分析. 与上面几个配合使用 | ||
-XX:+PrintClassHistogram | garbage collects before printing the histogram. | ||
-XX:+PrintTLAB | 查看TLAB空间的使用情况 | ||
XX:+PrintTenuringDistribution | 查看每次minor GC后新的存活周期的阈值 | Desired survivor size 1048576 bytes, new threshold 7 (max 15)
|