前言:
为啥要学jvm?工作上能用上吗?是不是就是为了应付面试的?
其实现在基本上调优这个事情大公司接触不到,小公司用不到,但是有句话说的好,学的越多,你面对问题的能力就越多,而且你的码会写的越好,打个比方,你在循环里疯狂创建对象的这种码你还会写码?如果线上出现了oom,你能立马解决,瞬间给你提升个职位,获得几声大佬,也是相当的nice,学习不是为了谁,就是为了默默的解决问题,装个X,这期内容偏多,谢谢耐心观看
1.自己负责的线上系统,到底如何合理设置JVM内存大小?
一个简单的支付系统的流程图:只要上过京东,tb等等网站,对这个流程应该再熟悉不过了【上图】
图中最核心的环节就是:就是用户发起支付请求的时候,会生成一个支付订单,这个支付订单需要记录清楚比如是谁发起支付?对哪个商品的支付?通过哪个渠道进行支付?还有发起支付的时间?等等多的信息。如果站在jvm的角度来讲,如果每日百万交易,就是每天都会在JVM中创建上百万个支付订单对象【如图】
需要考虑联想的问题是:
1.我们的支付系统需要部署多少台机器?
2.每台机器需要多大的内存空间?
3.每台机器上启动的JVM需要分配多大的堆内存空间?
4.给JVM多大的内存空间才能保证可以支撑这么多的支付订单再内存中的创建,而不会导致内存不够直接崩溃
支付系统每秒钟需要处理多少笔支付订单?
要想解决线上系统最核心的一个参数,也就是JVM堆内存大小的合理设置,这是首先要第一个需要自己预测出来的;
案例:
1.假设每天有100万个支付订单,那么一般用户交易的行为都会发生在每天的高峰期,例如中午午休,晚上饭后,假设每天的高峰期大概是几个小时,用100万平均分配到几个小时里,大概每秒100笔订单左右。假设支付系统部署了3台机器,每台机器实际上每秒大概处理30笔订单。也就是如图:
2.每个支付订单处理需要耗时多久呢?
如果用户发起一次支付请求,那么支付需要在JVM中创建一个支付订单的对象,填充数据进去,然后将这个支付订单写入数据库,还可能会处理一些其他的事情。【假设一次支付请求的处理,包含一个支付订单的创建,大概需要1秒钟的时间】,也就是大概一个流动的模型应该是每台机器一秒钟接收到30笔支付订单的请求,然后在JVM的新生代中创建了30个支付订单的对象,做了写入数据库等等处理。接着1秒之后,这30个支付订单就处理完毕了,然后对这些支付订单对象的引用回收,这些订单在JVM的新生代就是没有引用的垃圾对象了,接下来就是重复这个下一秒来30个支付订单的步骤了。
3.每个支付订单大概需要多大的内存空间?
Integer 4个字节,Long类型8个字节,list集合/数组另算,按照20个实例变量来计算,一般一个对象大概就是几百个字节,算500个字节,也就是不到1KB。每秒发起的支付请求对内存的占用,假设3台机器,每秒钟处理30笔支付订单的请求,那么在这1秒内,方法里的局部变量都是在引用这些支付订单的,那么30个支付订单,大概占用的内存空间是30*500字节=15000字节,大概也就是15kb,其实也是very
very small。
【小总结】
每秒钟30个支付请求,创建30个支付订单对象,也就是kb级别的内存空间,接着1秒钟过后,这30个对象就没有人引用了,就成了新生代中的垃圾了,下一秒再重复操作,直到有一刻,新生代几十万对象了,占据了几百MB的空间,新生代内存空间快要满了,就会触发年轻代Minor GC,把新生代中的垃圾对象给回收掉了,腾出空间。当然咯在真实的线上运行,肯定每秒还会创建大量的其他对象,可以提前估算,将之间估算的结果扩大10-20倍,也就是说除了在内存中创建支付订单对象还会创建数十种其他的对象,那么每秒钟创建出来被栈内存的局部变量引用的对象大致占据的内存空间就是几百KB-1MB之间,也是,循环多次之后,新生代的垃圾太多,触发Minor GC回收掉这些垃圾,这大概就是JVM层面的内存使用模型。
如果采用4核8G的机器来部署支付系统,JVM至少可以给4G以上的内存,新生代至少可以分配2G的内存,这样子就可以做到新生代每秒1mb左右内存,但是需要半小时到1小时才会新生代触发minor
gc,这样就大大降低了GC频率,如果业务量更大,可以横向扩张机器的部署,例如5台,10台,对JVM压力更小,当然成本也更高,更少的成本做更多的事,才叫优化,俺们不能就砸钱砸钱再砸钱。
频繁的young gc也就是年轻代gc会影响系统性能不?
yes,stop the world!!!
2.什么时候会触发垃圾回收?GC Roots概念?
面试官问:什么时候会触发垃圾回收机制?
答&#x