您好,我是湘王,这是我的头条号「湘王说」,欢迎您来,欢迎您再来~ 前面说过,JVM会将堆内存划分为年轻代、老年代两个区域。年轻代会将创建和使用完之后马上就要回收的对象放在里面,而老年代则将创建之后需要长期存在的对象放在里面。那么现在再来看一个比较具体的例子。 在电商系统中,支付系统大概处于这样的位置: 核心业务流程是: 假设日活在100W,那么JVM会创建和销毁100万个支付订单。那么问题来了: 1、需要部署多少台机器? 2、每台机器需要多大内存? 3、每台机器上启动的JVM需要分配多大堆内存空间? 4、JVM需要分配多大内存空间才能保证不会崩溃? 假设现在面试官坐在你对面,这灵魂四连问,你该怎么回答? 所以,需要合理地设置JVM堆参数,依据是: 首先要明确的,就是每秒钟要处理多少笔订单,这里是100万笔,那么: 1、每天100万单,都分别在两个高峰期:中午和下班后,每个高峰持续2小时,就是:2 × 2 = 4小时; 2、4小时 = 4 × 3600 = 14400秒; 3、100万 ÷ 14400秒 = 69.4单/秒,将系统性能弄紧凑一些,可以按150单/秒算; 4、假设支付系统部署了3台机器,且采取流量均分策略,那么每台机器至少每秒需要处理50个订单:支付订单请求 -> JVM创建支付订单对象 -> 写入数据库 -> 处理其他事务 -> 返回数据(不含网络请求时间损耗),假设理想状态下需要花费20毫秒时间,那么: l 接收到50笔支付订单请求 -> 在JVM年轻代中创建50个订单支付对象 -> 50 × 20毫秒=1秒之后处理完毕 l JVM将引用收回,这些对象就成了年轻代中的垃圾对象 l 下一秒继续重复上述过程 5、每笔支付订单所需的内存空间,依据实例对象及变量类型计算: l 每个实例对象的Java基本类型所占据的空间 + 引用对象所占据的空间 ≈ 1KB; l 50笔支付订单 = 50K内存空间; 6、JVM中的对象创建持续累积: 按照每秒消耗50KB的速度,如果没有垃圾回收,那么一台内存8G的机器大概会经过46个小时之后,将内存耗尽(8 × 1024 × 1024K = 8388608 / 50 = 167772 秒 / 3600 = 46小时); 服务器肯定不会将全部内存给应用运行,最多20%~40%,资源实际耗尽时间更短; 此时,垃圾回收出现,清场,腾位置,应用继续运行,这个过程循环往复; 7、真实的系统资源消耗,会比理想条件下的预估高出20倍以上。 所以,这里给出建议的配置方案: 1、无脑化通用配置:2C4G/4C8G; 2、建议有条件,只考虑4C8G及以上(硬件成本还会继续下降); 3、单台:-Xms3072M -Xmx3072M -Xmn2048M; 4、如果业务量更大,可以不只部署3台,可以是5台,10台或更多。 大促期间,访问量暴增10~100倍,因为压力骤增,部分请求出现超时甚至卡死、挂掉。这部分特别慢且未被释放的请求,可能会被GC误移入老年代,导致老年代里也出现越来越多的垃圾对象,由此: 年轻代资源不足 -> 年轻代频繁GC -> 老年代资源不足 -> 老年代频繁GC 依据经验,一般情况下: JVM栈上线初期:512K~1M足够 永久代上线初期:512M~1G足够 FAQ: 1、方法执行完后,栈帧立马出栈,因此该栈帧中的变量等数据立即就被回收了; 2、项目中托管给Spring管理的对象,带@Configration的都是长期存在于老年代; 3、自定义的bean对象如果不被定义为类对象就是朝生夕灭的,分配在年轻代中; 4、内存不够才会回收软引用对象,内存空间足够的话,不会回收软引用对象; 5、弱引用不管内存空间够不够,只能撑到下次垃圾回收之前,就被会回收; 6、垃圾回收的是软引用,弱应用和虚引用; 7、并不是新生代全部占满才minor gc,而是只要里面一块主要的内存区域满了就minor gc; 8、通过合理的估算方式尽量设大新生代 ,让系统在高峰期不进行垃圾回收。 感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~ 我在头条