业务开发中这些场景易触发FullGC,你遇到过几个?
数据库连接、文件流等资源未能及时关闭虽然不算是严格的内存泄漏,但如果大量连接或流对象由于异常等原因没有被正确关闭,它们所关联的Java对象和native memory就无法及时释放,也会导致内存压力激增,触发频繁的FullGC。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
对于我们程序员来说,FullGC既是陌生的老搭档也是熟悉的老朋友。如果它偶尔发生一两次,我们其实无需刻意处理;但若频率过高,就必须及时介入,否则会影响线上用户的正常使用体验。接下来,我们来聊聊几种容易触发FullGC的典型场景。
1、实际业务中FullGC的场景分析
每当服务器接收到请求后,都需要构建各式各样的业务对象。在实际开发中,我们创建的业务对象很可能是占用空间较大的对象(如果对象体积庞大,就会直接进入老年代存储),如下图所示:
图片
当我们创建完业务对象后,往往还需要调用其他服务获取业务数据。假设此时调用的其他服务出现了超时(比如服务C响应超时),情况就会变成下图所示:
图片
一旦发生这种情况,我们创建的业务对象就会常驻在JVM内存中。假设超时时间设置为15秒,那么在这15秒内,系统中的业务对象会一直占据内存空间。若在高并发场景下频繁出现此类情况,就会导致大量业务对象长期占用内存,如下图所示:
图片
此时JVM中就会出现年轻代对象不断向老年代转移的现象,如下图所示:
图片
由于老年代空间被持续涌入的对象不断占据,最终会导致即使总剩余空间还很多,却因内存碎片化严重而无法容纳新的业务对象,进而触发FullGC。
2、整理常见的引发FullGC的原因
FullGC会对老年代和新生代同时进行回收,通常还会伴随对元空间(或永久代)的清理,这往往会引起服务停顿,直接影响线上业务。
(1)老年代空间不足
当对象需要被分配到老年代,但老年代剩余空间无法满足需求时,就会触发FullGC。长期存活的对象不断进入老年代,正是导致老年代空间不足的常见原因。
JVM为每个对象定义了一个年龄计数器(记录在对象头中)。对象在Eden区诞生,经历一次YoungGC后若仍然存活,就会被移动到Survivor区,并且年龄增加1。当它的年龄增长到一定程度(默认为15,也可以通过参数调整),下一次Young GC时就会被晋升到老年代。如果此时老年代空间不足,就会触发Full GC。
(2)空间分配担保失败
在准备触发一次YoungGC时,会执行空间分配担保检查。在担保过程中,如果虚拟机检测到老年代最大可用连续空间小于新生代所有对象总空间,且HandlePromotionFailure=false(这个设置在jdk7中已不再支持,这一步骤在jdk7以后版本已被取消),那么就会执行一次FullGC。
在准备触发一次YoungGC时,会进行空间分配担保,在担保过程中发现老年代最大可用连续空间小于新生代所有对象的总空间,但是HandlePromotionFailure=true,继续检查发现老年代最大可用连续空间小于历次晋升到老年代对象的平均大小时,就会触发一次FullGC。
(3)调用 System.gc() 方法
在代码中直接调用System.gc()或Runtime.getRuntime().gc()会建议 JVM 执行 FullGC。需要注意的是这里只是建议,并非强制,但大多数情况下JVM都会执行。为了避免开发人员滥用,通常我们会通过参数-XX:+DisableExplicitGC来禁止这种显式的GC调用。
(4)内存泄漏
虽然老年代总空间很大,但如果存在内存泄漏,一些"垃圾对象"因为被意外的引用持有而无法被回收(典型的有ThreadLocal使用不当就会出现内存泄漏的问题)。每次YoungGC后,都有一批本应被回收的对象因为泄漏而被迫进入老年代,最终导致老年代空间使用达到回收阈值,触发FullGC。
(5)老年代碎片化严重
如果YoungGC后Survivor区存活对象正常晋升到老年代,但老年代也因碎片化严重而无法容纳这些对象,那么即使总的剩余空间还很充裕,也会触发FullGC来整理碎片。
偶尔一次FullGC通常不会造成问题,但如果FullGC频繁发生或者单次FullGC持续时间过长,这些都是需要我们重点关注的情况。
3、实际业务中常见的易导致FullGC场景
(1)雪崩效应
在系统中依赖其他服务返回的响应数据,如果其他服务返回响应超时,容易导致当前内存中数据激增进而触发FullGC。
(2)大对象分配
文件处理是常见业务场景,在解析文件时,如果用户上传一个上百兆的大文件,服务端一次性将其读入内存数组中,那么这个数组就是一个大对象,很可能直接在老年代分配。如果此时有多个用户同时上传大文件,就会迅速挤占老年代空间,进而触发FullGC。
(3)内存泄漏
一个后台任务系统,需要缓存一些任务执行上下文,开发人员常见的处理方案是将这些上下文对象放入一个静态的HashMap中(或者使用ThreadLocal)。由于静态集合的生命周期与类加载器相同(通常就是程序运行期间),这些上下文对象永远无法被回收。随着系统持续运行,这个HashMap会越来越大,最终导致老年代内存不足,触发频繁的FullGC。
(4)资源未关闭
数据库连接、文件流等资源未能及时关闭虽然不算是严格的内存泄漏,但如果大量连接或流对象因为异常等原因没有被正确关闭,它们所关联的Java对象和native memory就无法及时释放,也会导致内存压力激增,触发频繁的FullGC。
热门专题
热门推荐
V社联合创始人G胖调整角色:从主导开发转向赋能团队,释放创意生产力 近期一则消息引发游戏行业广泛关注:Valve联合创始人加布·纽维尔(“G胖”)在公司内部进行了一次重要角色转型。此次调整的关键原因,与他个人在公司中的特殊影响力息息相关。根据透露,这位创始人决定减少在具体游戏开发工作中的直接深度参与
红魔姜超透露:全新游戏平板将于四月或五月发布,承诺带来惊艳体验 游戏硬件领域即将迎来重磅更新。努比亚红魔游戏手机的产品线负责人姜超,近日通过社交媒体进行了一次颇具悬念的“前瞻剧透”,成功引发了广大游戏玩家和科技爱好者的高度关注。他明确指出,红魔全新一代游戏平板的发布日期已锁定在四月或五月,并使用了“
金铲铲之战S17天煞羁绊:效果解析与实战应用 在《金铲铲之战》S17赛季中,【天煞】是一个定位独特的专属羁绊,仅由5费英雄“劫”所携带。激活这一羁绊需要特定的前置条件——玩家必须在强化符文选择阶段获得【入侵者劫】。一旦成功解锁,劫将获得全新的技能机制,从而在战局中发挥出颠覆性的作用。 金铲铲之战S1
索尼调整第一方工作室阵容,王牌重制团队蓝点工作室正式“退出”核心名单 近日,索尼在其PlayStation Studios官方网站的更新中做出了一项关键调整,引发了游戏玩家和行业观察者的广泛关注:曾凭借《恶魔之魂:重制版》等作品赢得盛誉的蓝点工作室,已不再出现在索尼核心第一方工作室的名单之中。此次页
未来人类X98W移动工作站正式发布:重新定义移动端专业性能的新标杆 在专业移动计算领域,总有一些产品能够打破常规认知。近日,未来人类(TerransForce)正式在其官网上线了全新的X98W高性能移动工作站,并宣布将于本月内全面发售。这款设备的问世,无疑为那些在移动办公环境中仍需要桌面级别强悍性能





