当前位置:首页 > > 架构师社区
[导读]垃圾回收器老哥:你这样疯狂的嚯嚯对象,有考虑过我的感受吗?

“对象”的一生

像往常一样,早上10点到了公司,赵小八打开电脑收到了PM前一天晚上发来的推荐系统新需求,内心一万只草泥马飘过,思索了半天,打开IDEA开始了“愉快的”new对象之旅。

垃圾回收器老哥:你这样疯狂的嚯嚯对象,有考虑过我的感受吗?

赵小八:你谁啊?我new对象干你啥事?

垃圾回收器老哥:年轻人火气别这么大,既然你这么说那请耗子尾汁。

赵小八:呵,你哥我是被吓大的

垃圾回收器老哥:年轻人不讲武德...

没两天,小八翘着尾巴给PM说,功能上线了,刚没一会儿PM骂骂咧咧的找来了,这tm为啥有时候能出来内容有时候出不来啊,小八菊花一紧赶紧查起了问题,先搂监控接口平均耗时从200ms涨到了300ms,小八心想,我不过就多new了几个对象,怎么tm的影响会这么大,同时DBA同学反馈资源监控正常,看来只能搂业务日志看看了,可是业务日志也并没有什么问题,难道GC有问题?果不其然,GC日志像疯了一样的刷日志。小八赶紧让运维紧急回滚线上代码并dump了一份GC日志分析了起来。

现场代码复原

一次线上故障之Java对象的生命历程

上面这段代码是一个简化版的用户推荐系统,真实情况下加载需要加载的物料除机器学习物料、商业物料外,还有其他各种例如:运营物料、曝光物料、关系物料等等。

当一个真实用户请求过来之后,上面提到的这些物料就需要全部被加载进来。对象首先从新生代中被创建出来,接着经过一段时间GC后,最后存活下来的对象成功晋级到老年代,那么对象是在什么情况下成功晋级到老年代的呢?

case1:对象经历15次GC

  1. 小八疯狂的new对象,此时新创建的都被分配到Eden区,如下图:

一次线上故障之Java对象的生命历程

  1. 小八继续疯狂new对象,直到jvm老哥的Eden区放不下更多的对象了,于是触发了一次youngGC,通过这次youngGC之后,只有Context1对象被回收,剩余存活对象进入到了Survivor1里面,如下图:
一次线上故障之Java对象的生命历程
  1. 第一次youngGC结束后,小八又开始了new对象的神操作
一次线上故障之Java对象的生命历程
  1. 没一会儿,jvm又开始了youngGC,此时Eden区和Survivor1里面的存活对象全部移入到Survivor2中,剩余垃圾对象被回收。

一次线上故障之Java对象的生命历程

  1. 就这样反反复复经历了15次youngGC的折腾,还没有被垃圾回收掉的对象最终进入了Old区
一次线上故障之Java对象的生命历程

case2:动态年龄判断

  1. 小八疯狂的new对象
一次线上故障之Java对象的生命历程
  1. 小八继续疯狂new对象,直到jvm老哥的Enden区放不下更对的对象了,于是触发了一次youngGC
一次线上故障之Java对象的生命历程

经过此次youngGC后,剩余存活对象内存占用大小超过了survivor1区大小的50%,比如:survivor1区大小为50M,而进入到survivor1区的存活对象大小为30M,此时会将当前存活时间最久的对象直接晋升到老年代(存活时间:经历过GC次数最多的对象),此时Context2对象和Context3对象进入到老年代

一次线上故障之Java对象的生命历程

case3:空间担保机制

小八上线的用户推荐系统,JVM内存的划分情况为:整个堆大小为5G,其中老年代2.5G,新生代2.5G,其中新生代中Eden区:Survivor区=8:2,即Eden区大小为2G,两个Survivor区大小各为250M。

在晚高峰的时候一下子涌入1000人查看推荐列表,一个用户消耗的JVM内存达到了500kb,那么在一秒内就消耗了500M,那么就意味着4秒钟就会产生一次youngGC,假设每次GC后剩余的存活对象为300M,由于300M大小的存活对象无法在survivor区中存放下,此时就触发了空间担保机制。

  1. 小八疯狂的new对象
一次线上故障之Java对象的生命历程
  1. 直到发生第一次youngGC,但是一次youngGC后剩余的存活的对象大小Survivor区无法容纳下,此时所有存活对象会直接进入到Old区
一次线上故障之Java对象的生命历程

在新生代没有足够的内存存储新产生的对象时,老年代会判断自己的区域剩余的内存空间是否能够放得下历代youngGC后剩余存活对象(假设历代youngGC剩余存活对象大小为300M),假设此时老年代还有1G大小的可用内存,那么此次youngGC后剩余的存活对象将直接进入到老年代;假设此时老年代剩余可用内存大小为200M,那么就会触发一次OldGC,OldGC完成后产生的空闲空间大于300M,此时会将新生代的存活对象放入老年代,如果OldGC后剩余的空闲空间小于300M,那么不好意思,就会抛出OOM了。

一图总结Java对象流转情况

一次线上故障之Java对象的生命历程

上图便是整个Java对象一生经历的流程,流程图相对比较复杂一点,从上往下对照前面讲到的三种情况,相信还是比较容易理解的。

当然图中没有画图新生代触发OOM的情况,可以试想一下Eden区在什么时候会触发OOM?答案在下篇文章给出。

总结

通过一个实际线上案例,讲述了Java对象在不同情况下在JVM中经历的一生。通过本文大家可以尝试将该流程套用到自己公司的项目里面,来分析自己负责的项目是否有类似的问题,或者通过本篇文章来尝试优化自己的项目。另外本文的内容可能会有某些地方讲解的不合适,欢迎有问题的朋友和我私聊探讨。

在上篇文章中留了一个问卷调查,结论如下:总投票人数7人,其中最想了解的技术是SpringCloud,最喜欢的分享方式是图文结合。虽然投票人数比较少,但我相信投票的真实性,后续我会以这个结论为导向,分享更多实用的内容给大家。

打个小广告,年后大家有换个工作氛围的朋友或者身边有想法的朋友,快手研发、运维、产品、运营全部岗位都有你想要的坑位,各种新业务发展速度快,机会多多,面试流程反馈速度超快,欢迎朋友们自荐或者推荐朋友来一起做点有意义的事。




		
		
		
		

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭