【JVM-GC调优】

发布于:2025-05-09 ⋅ 阅读:(21) ⋅ 点赞:(0)

一、预备知识

  • 掌握GC相关的VM参数,会基本的空间调整
  • 掌握相关工具
  • 明白一点:调优跟应用、环境有关,没有放之四海而皆准的法则

二、调优领域

  • 内存
  • 锁竞争
  • cpu占用
  • io

三、确定目标

  • 【低延迟】:CMS、G1(低延迟、高吞吐)、ZGC(jdk12体验) 垃圾回收器
  • 【高吞吐量】:ParallelGC 垃圾回收器

四、FullGC前后的内存占用,考虑下面几个问题

  • 数据是不是太多?
    • resultSet = statement.sexecuteQuery(“select * from 大表”); 大量数据加载到堆内存,扛不住
  • 数据表示是否臃肿?
    • 对象图:查询时只查用到的字段
    • 对象大小:new Object() 都要占16个字节。Integer 24 int 4,如果内存占用过多,可以考虑从一些对象上进行瘦身,能用基本类型的就不用包装类型
  • 是否存在内存泄漏?
    • static Map map = ,静态的Map,不断向里面put数据,有可能导致溢出
    • 可以加上软、弱引用,
    • 缓存可以使用第三方缓存实现,尽量不要使用static Map map

五、新生代调优

  • 新生代特点
  1. 所有的new操作的内存分配非常廉价。
  2. 死亡对象的回收代价是零
  3. 大部分对象用过即死
  4. Minor GC的时间远远低于Full GC
  • 新生代越大越好吗?
    • 新生代空间大了,老年代空间就小了。很容易触发Full GC,暂停时间要比Minor GC暂停时间要长。
    • 新生代空间建议在四分之一以上二分之一以下
  • 晋升阈值配置得当,让长时间存活对象尽快晋升
    在这里插入图片描述

六、老年代调优

以CMS为例

  • CMS的老年代内存越大越好
  • 先尝试不做调优,如果没有Full GC那么已经很优了,否则先尝试调优新生代
  • 观察发生Full GC时老年代内存占用,将老年代内存预设调大1/4~1/3
    • -XX:CMSInitiatingOccupancyFraction=percent

七、案例

  1. Full GC和Minor GC频繁
  • 分析:说明空间紧张,如果是新生代空间紧张,当我们业务高峰期来了,大量对象被创建,很快新生代空间塞满了(幸存区空间紧张了),对象的晋升阈值就会降低,本来生存周期很短的对象,会被晋升到老年代中,进一步出发老年代垃圾回收导致Full GC频繁发生。
  • 解决:通过检查工具检查堆空间大小,确实发现新生代空间太小了,试着增大新生代内存(增加幸存区空间,增大晋升阈值),这样使一些生命周期较短的对象尽可能留在新生代,而不进入老年代,进而减少了老年代Full GC的发生
  1. 请求高峰期发生Full GC,单次暂停时间特别长(CMS)
  • 分析:到底是哪部分暂停时间特别长,查看GC日志,初始标记和并发标记都是比较快的,耗时的时重新标记(CMS在重新标记的时候会扫描整个的堆内存:需要扫描老年代和新生代内存),由于高峰期,新生代可能存在大量对象,导致重新标记会很慢。
  • 解决:在重新标记之前,可以先对新生代做一次垃圾回收,减少新生代对象数量,再次重新标记的时候,速度就快了
    在这里插入图片描述
  1. 老年代充裕情况下,发生Full GC(CMS jdk1.7)
  • 分析:导致Full GC的原因:1.空间不足,导致并发失败。2.空间碎片比较多。从CG日志看没有并发失败或者碎片过多导致的提示。说明老年代内存充裕。那就应该是jdk版本问题,1.7及以前版本,永久带空间不足,就会导致整个堆的一次Full GC出现,1.8及之后,改成了元空间(操作系统的内存空间),
  • 解决:增加永久带的内存空间

网站公告

今日签到

点亮在社区的每一天
去签到