前言
在之前的公司参与过一次秒杀xxxx活动设计与开发过程,涉及到了jvm优化问题,在这里记一下。
一、背景:
一个秒杀活动,秒杀时间是60s,TPS为3000,有三台机器-4核8g。
1.机器的jvm内存大小分析
一台8g内存的机器,大概分多少g给堆?
答:极限情况下6g。2g是os固有的;如果要用TProfiler、Arthas等监控工具,最多只能有4g给堆,推导出来监控工具大约要占1/4;
一般情况下4g差不多。
2.新老年代默认内存大小分析
新老生代默认是1:2,那么新生代:1333M。应当为:1333*0.9*0.8=960M
极限使用率90%,因为有s区,它要空着;
也不可能让eden区完全满着,大约不能超过80%的使用率。
3.峰值分析
如果峰值每秒3000笔,每台机器按理要达到1000笔,但我们要做一个20%-50%的预留,也就是每秒能抗住1200-1500笔。
4.订单对象分析、full GC原因分析
一个order对象大小(对象头、实例数据、对齐填充):不超过1k;
根据一些工具分析,一条链路会产生多少个对象,比方说20个:1k*20=20k;
假设单台要抗住1200笔:20k*1200=24M;
也就是每s产生24M的对象,年轻代堆内存可用大小是960M,能抗多少秒呢?
——960M/24M=40s; 只能抗40s。
只能抗40,没有压测的必要了。
并且,这个服务不可能只有促销在跑,还有其他的业务也再跑。
也就是40s后,young区不够用,会触发young GC。young GC有可能把对象以到老年代,促使老年代也达到GC条件,触发了full GC,full GC会STW,会导致服务卡死。
old区内存-2666M,促销的时候,old肯定不是空的,比如原来有2000M,26s后young GC后,有的对象晋升到了old区,比方晋升的所有对象的大小为600M,也就是old区一共2600M,那么会触发full GC。
46.对象的内存布局(对象头、实例数据、对齐填充)和对象的访问定位(句柄访问和直接指针)_simpleGq的博客-CSDN博客
5.在不加机器的情况下,怎么解决问题?
——给年轻代和老年代比例换一下,把1:2改成2:1。
- 年轻代:2666M
- 老年代:1333M
这种情况下,年轻代能抗80s了,抗过1分钟了,解决了问题。
但请各位注意:
G1和ZGC不能这么调,这两个GC不能改变新老年代比例;
改了之后,自适应策略、担保机制会失效。
先抗过这60s,如果秒杀不常用,晚上再把参数改回来。
6.图示
二、拓展
1.内存泄漏是在请求并不大的时候,通常造成OOM的主要原因是什么?
内存泄漏是在请求并不大的时候,通常造成OOM的主要原因;
形象的说,就是拿了一块内存不还了。
查看堆内存情况:
当程序比较卡的时候,排查问题原因的思路:
- top ,查看当前cpu有没有高不高
- jstack ,查看线程有没有发生死锁,或者锁由于某些原因未释放的问题
- jmap,分析堆内存情况
2.堆内存设置了4g,发现有不正常的full GC,此时查看堆内存才2g,为什么?
——方法区。启动项目的时候,元数据空间不够用,会抢占堆内存。这种情况jdk1.7根据突出,因为jdk1.7方法区占用了堆内存。
三、G1垃圾回收器
G1垃圾收集器使用前提:
如果达到了这些要求,可以直接用G1,可以不用调优了,因为你再调优,也达不到他的性能。