24 | 如何优化JVM内存分配?
24 | 如何优化JVM内存分配?
讲述:李良
时长11:08大小10.19M
JVM 内存分配性能问题
对象在堆中的生存周期
查看 JVM 堆内存分配
JVM 内存分配的调优过程
AB 压测
分析 GC 日志
参考指标
具体调优方法
总结
思考题
赞 8
提建议
精选留言(36)
- bro.2019-07-22堆外内存创建有两种方式:1.使用ByteBuffer.allocateDirect()得到一个DirectByteBuffer对象,初始化堆外内存大小,里面会创建Cleaner对象,绑定当前this.DirectByteBuffer的回收,通过put,get传递进去Byte数组,或者序列化对象,Cleaner对象实现一个虚引用(当内存被回收时,会受到一个系统通知)当Full GC的时候,如果DirectByteBuffer标记为垃圾被回收,则Cleaner会收到通知调用clean()方法,回收改堆外内存DirectByteBuffer
作者回复: 回答很全面,赞!
共 4 条评论62 - 迎风劲草2019-07-18老师,你的这个抢购场景下我理解是不是新生代越大越好,因为对象都是生命周期较短的对象。尽量在新生代中被回收掉。
作者回复: 也不是越大越好,因为新生代过大,会导致minor gc的停顿时间过长。 我们知道,如果新生代很快就满了,会以担保的方式将新增的对象直接分配到老年代,这样增加了老年代回收的成本,这个成本跟具体的垃圾收集器相关。所以我们需要适当的调大年轻代,将对象尽量留在年轻代回收。 如果调整太大,我们知道每次Minor GC分为对象标记和复制两个阶段,并且都是STW的,如果对象过于庞大,有可能标记时间要大于复制时间,这样反而适得其反。
23 - 天天向上2020-01-04如果你在线上环境或性能测试时,发现频繁的 GC,且是正常的对象创建和回收,这个时候就需要考虑调整 JVM 内存分配了。。有个问题,这个频率多久算频繁呢?
作者回复: 线上正常情况下FullGC出现的频率是非常低的,几天一次,一般FullGC如果出现一天超过一次,就已经算频繁了。 做性能压测的时候,FullGC的频率会高一些,但也是仅限于个位数。
共 2 条评论18 - QQ怪2019-07-16盲目增大堆内存可能会让吞吐量不增反减,堆内存大了,每次gc扫描对象也就越多也越需要花费时间,反而会适得其反
作者回复: 对的。合理设置堆内存大小,根据实际业务调整,不宜过大,也不宜过小。
10 - 钱2019-09-11课后思考及问题 1:JVM 内存分配不合理最直接的表现就是频繁的 GC,这会导致上下文切换等性能问题,从而降低系统的吞吐量、增加系统的响应时间。 频繁的GC,GC线程和应用线程会频繁的切入切出,所以,降低了系统的性能。 2:老师好,现在有这么一个问题,我们有一个定时任务跑一次大概会有2亿条数据一条数据大概40kb大小,一次大概7.4TB多的数据,分布式任务50台机器需要刷新2个多小时,我们需要持久化,为了提高性能做了异步发送MQ到另外的机器来持久化,不过MQ积压严重,数据跑一次耗时太长,有什么建议的优化思路嘛?拆分消息会加剧业务处理的复杂度,目前我能想到的是加机器加带宽。请老师给个优化的思考?展开
作者回复: 优化传输性能,例如使用特定的数据结构序列化与反序列化传输数据(protobuff序列化),并且提高单台服务并行处理能力。
共 3 条评论6 - 我又不乱来2019-07-16超哥,有两个疑问。 当第一次创建对象的时候 eden 空间不足会进行一次minor gc把存活的对象放到from s区。如果这个时候from s放不下。会发生一次担保进入老年代吗? 当一次创建对象的时候eden空间不足进入from s区。当第二次创建对象的时候eden空间又不足了,这个时候会把,eden和第一次存在from s 区的对象进行gc 存活的放在 to s区,to s区空间不足,进行担保放入老年代?这样的理解对吗。展开
作者回复: 对的,细节把握的很好! 前提是老年代有容量这些对象的空间,才会进行分配担保。如果老年代剩余空间小于每次minor gc晋升到老年代的平均值,则会发起一次Full GC。
6 - 恰饭哒2019-07-16超哥好,我们经常发现生产环境内存使用超过90%持续3分钟,没有outofmer, dump下来堆没有发现问题,这种情况每不确定几小时就会一次,求解答
作者回复: 你好,某一时间段高峰值的访问可能会有这种情况,JVM会最大可能进行对象的回收,防止内存溢出异常的发生。如果不是内存泄漏,或者瞬时并发量大大超过预期并发量的情况,几乎很少发生内存溢出异常。 建议结合内存持续占用率以及Full GC发生的频率来分析调优。
共 3 条评论4 - 考休2019-11-13根据老师的教程,在测试项目中,将年轻代的大小调整为3g,发现的确性能提升了,Mirror GC的次数也大大减少,但是Full GC的次数也明显多了几倍,这个是因为年轻代的空间过大,压缩了老年代的内存大小吗? java -jar -Xms4g -Xmx4g -Xmn3g heapTest-0.0.1-SNAPSHOT.jar
作者回复: 是的
共 3 条评论3 - 风轻扬2019-09-10老师,如果允许分配担保机制失败。那即使老年代的空间不足以吃下年轻代的对象。jvm也会冒险进行minor gc的。gc之后,如果老年代还是吃不下对象,这个时候才会Full GC。那关闭这个分配担保机制,感觉好一点啊,反正有Full GC兜底呢😃
作者回复: 打开分配担保机制,是为了避免Full GC过于频繁。
3 - -W.LI-2019-07-16老师好!堆外缓存实在FGC的时候回收的吧。 AdaptiveSizePolicy这个参数是不是不太智能啊?我项目4G内存默认开启的AdaptiveSizePolicy。发现只给年轻代分配了136M内存。平时运行到没啥问题,没到定时任务的点就频繁FGC。每次定时任务执行完,都会往老年代推40多M,一天会堆300多M到老年代,也不见它把年轻代调大。用的parNew+CMS。后来把年轻代调整到1G(单次YGC耗时从20ms增加到了40ms),每天老年代内存涨20M左右。展开
作者回复: 这个会根据我们的内存创建大小合理分配内存,并不仅仅考虑对象晋升的问题,还会综合考虑回收停顿时间等因素。 针对某些特殊场景,我们可以手动来配置调优。
3 - 刘梦春2021-01-21堆内存最多4g 年轻代3g 1g的老年代怎么给年轻代做担保?1
- Levvy2019-12-04最大堆内存1593M 还有124M 这俩数字是在哪看的,我怎么找不到
作者回复: 在jmap -heap pid运行之后,有一个MaxHeapSize,这个就是1953M,还有一个是NewSize以及OldSize,加起来就是初始化的124M大小。
共 2 条评论1 - 小笨蛋2019-09-17请问堆内存的分配有没有一个大概的标准😭既然都提到了不能太大也不能太小
作者回复: 需要根据自己的项目来具体做配置,如果不清除具体需要的配置大小,使用默认配置就可以了
1 - 又双叒叕是一年啊2019-08-29你好,请问G1调优能不能也讲讲。主要应该注意些什么和cms这种调优的差异
作者回复: 嗯,在后面的答疑课堂中讲到了,有问题欢迎提出
1 - 披荆斩棘2021-11-22超哥,我最近在学并行编程过程中,学master- work并行程序设计模式,运行书中给的示例,就是“用线程计算1到10000的3次方和”,我的电脑是8核20g内存,用一个线程和用5个线程去跑,跑出来时间差不多,非常疑惑,按道理时间是1线程跑的1/5吧
- aroll2021-03-24netty4通过引用计数,来处理缓冲区的复用与回收
- 李飞2021-03-03老师,MinorGC频率多少比较合适呢?
- 猪大强2020-12-22过分的调大堆内存,会增加MinorGC扫描的时间的,在高并发的情况下如何解决呢?
- slofish2020-06-30实战项目中真的发生大量gc. 增大内存也不能根本解决问题,应该明确什么原因导致这些对象不被回收,而不是盲目增加,指标不治本1
- Geek_323c912020-05-19不知道能不能收到回复,我有个以为,网上查了很多资料 也没得到一个答案,-c 1000 -n 100000 和 -c 100000 和-n 10000的区别是什么 自己压测 怎么调整这2个值
作者回复: -n表示请求次数 -c表示并发数,-c 1000 -n 100000表示总的请求100000次,且并发用户数为1000。-c 100000 和-n 10000表示总的请求10000次,并发用户数为100000。