文章目录
- 版权声明
- 解决GC问题的手段
- 优化基础JVM参数
- -Xmx 和 –Xms
- -XX:MaxMetaspaceSize 和 –XX:MetaspaceSize
- -Xss虚拟机栈大小
- ‐XX:SurvivorRatio和‐XX:MaxTenuringThreshold
- -XX:+DisableExplicitGC
- 案例:垃圾回收器的选择
- 复习:垃圾回收器的组合关系
- 背景
- 思路
- 案例:优化垃圾回收器的参数
- 解决方案
版权声明
- 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明,所有版权属于黑马程序员或相关权利人所有。本博客的目的仅为个人学习和交流之用,并非商业用途。
- 我在整理学习笔记的过程中尽力确保准确性,但无法保证内容的完整性和时效性。本博客的内容可能会随着时间的推移而过时或需要更新。
- 若您是黑马程序员或相关权利人,如有任何侵犯版权的地方,请您及时联系我,我将立即予以删除或进行必要的修改。
- 对于其他读者,请在阅读本博客内容时保持遵守相关法律法规和道德准则,谨慎参考,并自行承担因此产生的风险和责任。
- 本博客中的部分观点和意见仅代表我个人,不代表黑马程序员的立场。
解决GC问题的手段
- 解决GC问题的手段中,比较推荐前三种手段
- 优化基础JVM参数
- 基础JVM参数的设置不当,会导致频繁产生FULL GC
- 减少对象产生
- 大多数场景下的FULL GC是由于对象产生速度过快导致,减少对象的产生可以有效地缓解FULL GC的发生
- 更换垃圾回收器
- 选择合适当前业务场景的垃圾回收器,可以减少延迟、提高吞吐量
- 优化垃圾回收器参数
- 优化垃回收器的参数,能在一定程度上提升GC效率
优化基础JVM参数
-Xmx 和 –Xms
-Xmx
:设置的是最大堆内存,但是由于程序是运行在服务器或者容器上,计算可用内存时,要将元空间、操作系统、其它软件占用的内存排除掉。- 案例: 服务器内存4G,操作系统+元空间最大值+其它软件占用1.5G,-Xmx可以设置为2g。
- 最合理的设置方式应该是根据最大并发量估算服务器的配置,然后再根据服务器配置计算最大堆内存的值。
- -Xms用来设置初始堆大小,建议将-Xms设置的和-Xmx一样大,有以下几点优势
- 运行性能更好,堆的扩容是需要向操作系统申请内存,会导致程序性能短期下降。
- 可用性问题,如果在扩容时其他程序正在使用大量内存,很容易因为操作系统内存不足分配失败。
- 启动速度更快,如果初始堆太小,Java 应用程序启动会变得很慢,因为 JVM 被迫频繁执行垃圾收集,直到堆增长到更合理的大小。为获得最佳启动性能,请将初始堆大小设置为与最大堆大小相同。
-XX:MaxMetaspaceSize 和 –XX:MetaspaceSize
-XX:MaxMetaspaceSize=值
参数指最大元空间大小,默认值比较大,如果出现元空间内存泄漏会让操作系统可用内存不可控,建议根据测试情况设置最大值,一般设置为256m。-XX:MetaspaceSize=值
参数指到达该值之后会触发FULLGC,后续触发时机JVM会自行计算。如果设置为MaxMetaspaceSize
一样大,就不会FULLGC,但是对象也无法回收。
-Xss虚拟机栈大小
- 如果不指定栈的大小,JVM 将创建一个具有默认大小的栈。大小取决于操作系统和计算机的体系结构。比如Linux x86 64位 1 M B 1MB 1MB,如果不需要用到这么大的栈内存,可以将此值调小节省内存空间,合理值为 256 k – 1 m 256k – 1m 256k–1m之间。
- 使用: − X s s 256 k -Xss256k −Xss256k
‐XX:SurvivorRatio和‐XX:MaxTenuringThreshold
- 不建议手动设置的参数
- 由于JVM底层设计极为复杂,一个参数的调整也许让某个接口得益,但同样有可能影响其他更多接口。
-Xmn
年轻代的大小,默认值为整个堆的 1 / 3 1/3 1/3,可以根据峰值流量计算最大的年轻代大小,尽量让对象只存放在年轻代,不进入老年代。但是实际场景中,接口的响应时间、创建对象的大小、程序内部还会有一些定时任务等不确定因素都会导致这个值的大小并不能仅凭计算得出,如果设置该值要进行大量的测试。G1垃圾回收器尽量不要设置该值,G1会动态调整年轻代的大小。
‐XX:SurvivorRatio
伊甸园区和幸存者区的大小比例,默认值为 8 8 8。‐XX:MaxTenuringThreshold
最大晋升阈值,年龄大于此值之后,会进入老年代。另外JVM有动态年龄判断机制:将年龄从小到大的对象占据的空间加起来,如果大于 s u r v i v o r survivor survivor区域的 50 50% 50,然后把等于或大于该年龄的对象,放入到老年代。
-XX:+DisableExplicitGC
-XX:+DisableExplicitGC
禁止在代码中使用 S y s t e m . g c ( ) System.gc() System.gc(), S y s t e m . g c ( ) System.gc() System.gc()可能会引起 F U L L G C FULLGC FULLGC,在代码中尽量不要使用。使用 D i s a b l e E x p l i c i t G C DisableExplicitGC DisableExplicitGC参数可以禁止使用 S y s t e m . g c ( ) System.gc() System.gc()方法调用。-XX:+HeapDumpOnOutOfMemoryError
:发生 O u t O f M e m o r y E r r o r OutOfMemoryError OutOfMemoryError错误时,自动生成 h p r o f hprof hprof内存快照文件。-XX:HeapDumpPath=<path>
:指定 h p r o f hprof hprof文件的输出路径。- 打印GC日志
- JDK8及之前 :
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:文件路径
- JDK9及之后 :
-Xlog:gc*:file=文件路径
- JDK8及之前 :
案例:垃圾回收器的选择
复习:垃圾回收器的组合关系
背景
- 小李负责的程序在高峰期遇到了性能瓶颈,团队从业务代码入手优化了多次也取得了不错的效果,这次他希望能采用更合理的垃圾回收器优化性能。
思路
- 编写Jmeter脚本对程序进行压测,同时添加RT响应时间、每秒钟的事务数等指标进行监控。
- 选择不同的垃圾回收器进行测试,并发量分别设置50、100、200,观察数据的变化情况
- JDK8 下 ParNew + CMS 组合 : -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
- 默认组合 : PS + PO
- JDK8使用g1 : -XX:+UseG1GC
- JDK11 默认 g1
案例:优化垃圾回收器的参数
- 优化的案例:CMS的并发模式失败(concurrent mode failure)现象。由于CMS的垃圾清理线程和用户线程是并行进行的,如果在并发清理的过程中老年代的空间不足以容纳放入老年代的对象,会产生并发模式失败。
- 并发模式失败会导致Java虚拟机使用Serial Old单线程进行FULLGC回收老年代,出现长时间的停顿。
解决方案
- 减少对象的产生以及对象的晋升
- 增加堆内存大小
- 优化垃圾回收器的参数,如
-XX:CMSInitiatingOccupancyFraction=值
,当老年代大小到达该阈值时,会自动进行CMS垃圾回收,通过控制这个参数提前进行老年代的垃圾回收,减少其大小。JDK8中默认参数值为-1
,根据其他几个参数计算出阈值:((100 - MinHeapFreeRatio) + (double)(CMSTriggerRatio * MinHeapFreeRatio) / 100.0)
该参数设置完是不会生效的,必须开启-XX:+UseCMSInitiatingOccupancyOnly
参数。
- 调整之后的效果