Java 性能调优实战
刘超
前金山软件技术经理
59174 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
开篇词 (1讲)
模块一 · 概述 (2讲)
结束语 (1讲)
Java 性能调优实战
15
15
1.0x
00:00/00:00
登录|注册

24 | 如何优化JVM内存分配?

具体调优方法
参考指标
分析GC日志
AB压测
思考题
JVM内存分配的调优过程
查看JVM堆内存分配
对象在堆中的生存周期
JVM内存分配性能问题
总结
性能问题
如何优化JVM内存分配

该思维导图由 AI 生成,仅供参考

你好,我是刘超。
JVM 调优是一个系统而又复杂的过程,但我们知道,在大多数情况下,我们基本不用去调整 JVM 内存分配,因为一些初始化的参数已经可以保证应用服务正常稳定地工作了。
但所有的调优都是有目标性的,JVM 内存分配调优也一样。没有性能问题的时候,我们自然不会随意改变 JVM 内存分配的参数。那有了问题呢?有了什么样的性能问题我们需要对其进行调优呢?又该如何调优呢?这就是我今天要分享的内容。

JVM 内存分配性能问题

谈到 JVM 内存表现出的性能问题时,你可能会想到一些线上的 JVM 内存溢出事故。但这方面的事故往往是应用程序创建对象导致的内存回收对象难,一般属于代码编程问题。
但其实很多时候,在应用服务的特定场景下,JVM 内存分配不合理带来的性能表现并不会像内存溢出问题这么突出。可以说如果你没有深入到各项性能指标中去,是很难发现其中隐藏的性能损耗。
JVM 内存分配不合理最直接的表现就是频繁的 GC,这会导致上下文切换等性能问题,从而降低系统的吞吐量、增加系统的响应时间。因此,如果你在线上环境或性能测试时,发现频繁的 GC,且是正常的对象创建和回收,这个时候就需要考虑调整 JVM 内存分配了,从而减少 GC 所带来的性能开销。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

JVM内存分配调优是提高系统性能的关键一环。频繁的GC表现出内存分配不合理,直接影响系统吞吐量和响应时间。了解对象在堆中的生存周期和JVM堆内存的分配情况是调优的基础。通过观察应用服务的运行情况和分析GC日志,可以发现性能问题并进行调优。调整堆内存大小、优化年轻代和老年代的比例、设置Eden、Survivor区比例等方法都可以有效提高系统性能。JVM内存调优通常与GC调优互补,结合上一讲的内容,可以完成JVM调优。在进行性能压测后,如果没有发现突出的性能瓶颈,可以继续使用JVM默认参数。但在需要优化的情况下,可以根据实际情况调整内存分配,相信会有新的收获。文章还提到了堆外内存在NIO的Socket通信中的应用,期待读者的进一步探讨。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 性能调优实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(36)

  • 最新
  • 精选
  • bro.
    堆外内存创建有两种方式:1.使用ByteBuffer.allocateDirect()得到一个DirectByteBuffer对象,初始化堆外内存大小,里面会创建Cleaner对象,绑定当前this.DirectByteBuffer的回收,通过put,get传递进去Byte数组,或者序列化对象,Cleaner对象实现一个虚引用(当内存被回收时,会受到一个系统通知)当Full GC的时候,如果DirectByteBuffer标记为垃圾被回收,则Cleaner会收到通知调用clean()方法,回收改堆外内存DirectByteBuffer

    作者回复: 回答很全面,赞!

    2019-07-22
    4
    65
  • 迎风劲草
    老师,你的这个抢购场景下我理解是不是新生代越大越好,因为对象都是生命周期较短的对象。尽量在新生代中被回收掉。

    作者回复: 也不是越大越好,因为新生代过大,会导致minor gc的停顿时间过长。 我们知道,如果新生代很快就满了,会以担保的方式将新增的对象直接分配到老年代,这样增加了老年代回收的成本,这个成本跟具体的垃圾收集器相关。所以我们需要适当的调大年轻代,将对象尽量留在年轻代回收。 如果调整太大,我们知道每次Minor GC分为对象标记和复制两个阶段,并且都是STW的,如果对象过于庞大,有可能标记时间要大于复制时间,这样反而适得其反。

    2019-07-18
    25
  • 天天向上
    如果你在线上环境或性能测试时,发现频繁的 GC,且是正常的对象创建和回收,这个时候就需要考虑调整 JVM 内存分配了。。有个问题,这个频率多久算频繁呢?

    作者回复: 线上正常情况下FullGC出现的频率是非常低的,几天一次,一般FullGC如果出现一天超过一次,就已经算频繁了。 做性能压测的时候,FullGC的频率会高一些,但也是仅限于个位数。

    2020-01-04
    2
    20
  • QQ怪
    盲目增大堆内存可能会让吞吐量不增反减,堆内存大了,每次gc扫描对象也就越多也越需要花费时间,反而会适得其反

    作者回复: 对的。合理设置堆内存大小,根据实际业务调整,不宜过大,也不宜过小。

    2019-07-16
    10
  • 课后思考及问题 1:JVM 内存分配不合理最直接的表现就是频繁的 GC,这会导致上下文切换等性能问题,从而降低系统的吞吐量、增加系统的响应时间。 频繁的GC,GC线程和应用线程会频繁的切入切出,所以,降低了系统的性能。 2:老师好,现在有这么一个问题,我们有一个定时任务跑一次大概会有2亿条数据一条数据大概40kb大小,一次大概7.4TB多的数据,分布式任务50台机器需要刷新2个多小时,我们需要持久化,为了提高性能做了异步发送MQ到另外的机器来持久化,不过MQ积压严重,数据跑一次耗时太长,有什么建议的优化思路嘛?拆分消息会加剧业务处理的复杂度,目前我能想到的是加机器加带宽。请老师给个优化的思考?

    作者回复: 优化传输性能,例如使用特定的数据结构序列化与反序列化传输数据(protobuff序列化),并且提高单台服务并行处理能力。

    2019-09-11
    3
    7
  • 我又不乱来
    超哥,有两个疑问。 当第一次创建对象的时候 eden 空间不足会进行一次minor gc把存活的对象放到from s区。如果这个时候from s放不下。会发生一次担保进入老年代吗? 当一次创建对象的时候eden空间不足进入from s区。当第二次创建对象的时候eden空间又不足了,这个时候会把,eden和第一次存在from s 区的对象进行gc 存活的放在 to s区,to s区空间不足,进行担保放入老年代?这样的理解对吗。

    作者回复: 对的,细节把握的很好! 前提是老年代有容量这些对象的空间,才会进行分配担保。如果老年代剩余空间小于每次minor gc晋升到老年代的平均值,则会发起一次Full GC。

    2019-07-16
    6
  • 恰饭哒
    超哥好,我们经常发现生产环境内存使用超过90%持续3分钟,没有outofmer, dump下来堆没有发现问题,这种情况每不确定几小时就会一次,求解答

    作者回复: 你好,某一时间段高峰值的访问可能会有这种情况,JVM会最大可能进行对象的回收,防止内存溢出异常的发生。如果不是内存泄漏,或者瞬时并发量大大超过预期并发量的情况,几乎很少发生内存溢出异常。 建议结合内存持续占用率以及Full GC发生的频率来分析调优。

    2019-07-16
    4
    4
  • 考休
    根据老师的教程,在测试项目中,将年轻代的大小调整为3g,发现的确性能提升了,Mirror GC的次数也大大减少,但是Full GC的次数也明显多了几倍,这个是因为年轻代的空间过大,压缩了老年代的内存大小吗? java -jar -Xms4g -Xmx4g -Xmn3g heapTest-0.0.1-SNAPSHOT.jar

    作者回复: 是的

    2019-11-13
    3
    3
  • 风轻扬
    老师,如果允许分配担保机制失败。那即使老年代的空间不足以吃下年轻代的对象。jvm也会冒险进行minor gc的。gc之后,如果老年代还是吃不下对象,这个时候才会Full GC。那关闭这个分配担保机制,感觉好一点啊,反正有Full GC兜底呢😃

    作者回复: 打开分配担保机制,是为了避免Full GC过于频繁。

    2019-09-10
    3
  • -W.LI-
    老师好!堆外缓存实在FGC的时候回收的吧。 AdaptiveSizePolicy这个参数是不是不太智能啊?我项目4G内存默认开启的AdaptiveSizePolicy。发现只给年轻代分配了136M内存。平时运行到没啥问题,没到定时任务的点就频繁FGC。每次定时任务执行完,都会往老年代推40多M,一天会堆300多M到老年代,也不见它把年轻代调大。用的parNew+CMS。后来把年轻代调整到1G(单次YGC耗时从20ms增加到了40ms),每天老年代内存涨20M左右。

    作者回复: 这个会根据我们的内存创建大小合理分配内存,并不仅仅考虑对象晋升的问题,还会综合考虑回收停顿时间等因素。 针对某些特殊场景,我们可以手动来配置调优。

    2019-07-16
    3
收起评论
显示
设置
留言
36
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部