JVM
2020-12-12 17:07:50 0 举报
JVM内容
作者其他创作
大纲/内容
S1 100M
堆
6M*10
亿级流量电商项目JVM调优实战
本地方法栈
300单,每单1kb
4核8G
情况分析:1.正常情况下,14S后,Eden区将被占满,进行MinorGC,将还未被废弃的对象放到S区中,假设对象有效时间只有1s,那么将只有一组对象,大概60M。但是由于对象动态年龄判断机制,对象将不会保存到S区中,而是直接放到老年代中,那么经过一段时间以后,老年代将会被填满,触发FullGC。
java -Xms:3072M -Xmx:3072M -Xmn:2048M-Xss:1M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M -jar microservice-eureka-server.jar
S2
触发STW机制
MinorGC
N
特殊机制
对象保存到老年代
1.整个堆分为年轻代和老年代,比例为1:2,年轻代包含Eden和S1以及S2,比例为8:1:1。2.GC是单独线程3.STW:即stop the world,停止所有线程,执行full gc,根据可达性分析算法来查询废弃对象,进行销毁。4.STW存在意义:当进行Full gc的时候,由于正在使用可达性分析算法来查找废弃对象,如果此时对象关系是变动的,那么可能会导致之前已经查询到的对象状态被改变,导致无法确定对象的状态,也就无法进行GC,会导致重复计算可达性信息,所以要进行STW。
老年代1G
对象动态年龄判断:当前放对象的Survivor区域里(其中一块区域,放对象的那块s区),一批对象的总大小大于这块Survivor区域内存大小的 50%(-XX:TargetSurvivorRatio可以指定),那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了, 例如Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会 把年龄n(含)以上的对象都放入老年代。这个规则其实是希望那些可能是长期存活的对象,尽早进入老年代。对象动态年 龄判断机制一般是在minor gc之后触发的。
操作数栈
T3
程序计数器
Eden 1600M
大对象直接进入老年代:大对象就是需要连续内存空间的较大的对象,通过参数-XX:PretenureSizeThreshold可以设置大对象的大小,如果超过这个大小,那么对象将直接被放到老年代。这样的好处是减少因为复制大对象所需要花费较长时间。
S1
局部变量
对象保存到S1/S2,并且对象年龄+1
Full gc
考虑到其他内容,比如优惠券、积分等,对象扩大20倍
S1 200M
Y
Older(老年代)
new Object()
60M/S
情况分析:1.正常情况下,14S后,Eden区将被占满,进行MinorGC,将存活对象放到S区中,但是由于对象动态年龄判断机制,对象将不会保存到S区中,而是直接放啊都老年代中,那么在第3次Minor GC,将会有超过2G的对象保存到老年代中,此时将触发FullGC。
14S占满Eden
T2
大促场景,订单集中在几分钟内
300KB*20
情况分析:1.对象正常存活时间大概1S,1S后对象将会被废弃,但是要等到GC的时候才会在内存中清楚。当前情况下,对象在到达S1区后,经过1S,对象肯定已经废弃,那么在下一次minor gc的时候,对象所占用的空间将会被释放,也就是不会有对象放到老年代中,大大减少了Full gc的次数
1.作用:用于记录每个线程当前执行的位置,以免其他线程抢占的CPU之后再回到当前线程找不到执行位置。2.线程间独立。
Eden
JVM
方法区
Eden 800M
常规GC流程
tips:方法调用在栈中都是向上累计分配空间的,当上层方法调用结束后会收回对应栈空间,回到下方栈空间之前执行位置,即main方法的程序计数器所指向的位置。
逃逸分析:当对象只在方法内部被使用,而没有与外部方法进行关联的时候,JVM会将对象创建在栈中,而不是堆中。这样的好处是可以让对象随着方法的结束而被销毁,而不需要等到GC才能被释放,减少了GC压力
此时JVM参数
动态链接
S2 100M
每日点击一亿+
老年代2G
标量替换:当对象逃逸了,那么这时候JVM会将完整的对象拆分为几个标量,保存在栈中,这样就不需要一块连续的大的内存空间来保存对象,防止内存不足。
方法出口
对象年龄>=15ORS1/S2内存无法保存GC后剩余对象
main栈帧
修改JVM参数
老年代空间分配担保机制:年轻代每次minor gc之前JVM都会计算下老年代剩余可用空间 如果这个可用空间小于年轻代里现有的所有对象大小之和(包括垃圾对象) 就会看一个“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了 如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的平均大小。 如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾, 如果回收完还是没有足够空间存放新的对象就会发生\"OOM\" 当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老年代可用空间,那么也会触发full gc,full gc完之后如果还是没有空间放minor gc之后的存活对象,则也会发生“OOM”
再考虑其他操作,比如订单查询等,对象再扩大10倍
日活用户500w+
1.每个线程拥有自己的栈2.每个方法在栈中有独立的分区,叫做栈帧3.每个栈帧中分为4个部分,即局部变量,操作数栈,动态链接,方法出口,其中:局部变量用于保存方法内部变量信息,包含引用的堆内存地址,操作数栈用于保存即将进行内部运算的操作数,动态链接用于指向被调用方法(即方法内部的方法入口)入口内存地址,方法出口用于指向调用者当前操作数栈以及本方法返回信息。
Eden(伊甸园)
保存
成功购买用户50w+
长期存活对象进入老年代:每个对象从创建开始,年龄为0,经过一次GC后仍然存活,那么年龄+1,如果经过一定次数(默认15次)的GC后,对象仍然存活,那么对象将被保存到老年代。
T1
栈
S2 200M
1.作用:用于保存:常量+静态变量+类元信息2.线程间独立
Eden存满?
compute栈帧
老年代是否足够保存对象?
1.作用:当JVM执行native方法的时候锁分配的内存空间。2.线程间独立。
每秒1000单+
public int compute(){ int a = 3; int b = 5; int c = a+b; return c;}public void main (){ int res = compute();}
0 条评论
下一页