Jvm参数设置-JVM(八)

上篇文章说了逃逸分析和标量,代码实例解析了内存分配先从eden区域开始,当内存不足的时候,才会进入s0和s1,发生yangGC,之后大内存会放入old,因为我们昨天程序运行了一个45M的对象,于是小对象在eden,对象在老年代。

Jvm创建对象之内存分配-JVM(七)

  • 大对象直接进入老年代

大对象指需要连续空间存储的对象(字符串,数组)。正常是eden放不下进入老年代,但是我们也可以用参数配置,当大于这个参数直接进入老年代。

-XX:PretenureSizeThreshold=1000 -XX:+UseSerialGC

只有Serial和ParNew垃圾收集器才生效的。

Jvm参数设置-JVM(八)_第1张图片

记得参数后面还有加个打印gc的参数-XX:PrintGCDetails

当我们设置了这个参数之后,则看到一个7M的数据明明可以放在eden,但是直接进入了老年代,前面的百分之14并不是我们代码的7M对象,而是eden自己内部的对象。

有什么优点呢?

可以避免大对象内存gc复制操作而降低效率。

  • 长期存活的也会进入老年代

既然是分代思想管理的,就必须知道对象哪些属于老年代,哪些属于年轻代,于是每个对象都有他的年龄。

如果对象eden经过第一次yangGc还能存活,并且被survivor容纳,则会进入survivor,这时候年龄会随着每次复制移动而增长,当年龄到了15岁(默认是15,CMS收集器默认6岁),就会进入老年代。

可以通过参数配置年龄代-XX:MaxTenuringThreshold

  • 对象动态年龄判断机制

我们有一个对象在eden,当yangGC后,状态还是活跃状态,则会进入survivor,但也会有一种情况直接进入老年代。

当一批对象大于等于survivor的百分之50,这时候则会把survivor里大于等于1年龄代的对象全部都移动到老年代里去,这样做的目的也是为了减少存活时间长的对象避免太多的复制移动。

  • 场景实例
  1. 亿级流量电商(每日点击上亿次)
  2. 如果平均每个用户点击二三十次,那么就有500万个日活用户。
  3. 付费转换率是百分之10,那就是每天50万单子

(如果是正常三四小时内完成,那么每秒几十订单影响不大)

  1. 但如果高峰场景,每秒1000订单

订单系统是4核8G,300单每秒,三台机器

假设订单表几十个字段,阿里巴巴规范表字段不可以太多,每个订单有300个字,大概1KB。

  1. 那么300单*1KB = 300kb,每秒300KB

下单还能涉及到其他对象,比如库存,优惠卷,积分等。

6、300kb*20*10 = 60000 KB每秒

(每秒大概60M进入eden,这60M对象大概会在1s都会变成垃圾对象)

Jvm参数设置-JVM(八)_第2张图片

可以通过命令指定堆位3G,对最大值也3G,栈帧1M,元空间512M。

Java -Xms3072M -Xmx3072M -Xss1M -XX:MetaspaceSize=512M

-XX:MaxMetasspaceSize=512M -jar microservice-sureka.jar

这时候知道通过亿级流量日活大概有60M的数据进入eden,14s的60M就会占满我们的eden,满了则会yangGC,这时候前面13s的对象都会被垃圾回收,因为他是垃圾对象,因为回收的时候会STW(stop the word),导致最后1s的还没被回收,这时候eden因为对象动态年龄判断机制,直接进入了old,在old里1s后就属于垃圾了,之后old满之后则会发生fullGC,很明显,这样频繁发生fullGC是不合理的。

所以我们设置jvm参数是要根据实际情况来设置的,那么这种怎么设置呢?

Java -Xms3072M -Xmx3072M -Xss1M -XX:MetaspaceSize=512M -Xmn2048

-XX:MaxMetasspaceSize=512M -jar microservice-sureka.jar

这时候会发生什么呢?

老年代只剩下1个G,年轻代有2个G,那么eden就是1.6G,S0和S1都是200M。

这时候则能放的下S0,不会触发动态年龄判断,这时候则会直接在SURVIVOR会回收,不会进入老年代。

你可能感兴趣的:(后端,jvm,java,开发语言)