0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

完蛋!我被 Out of Memory 包围了!

京东云 来源:jf_75140285 作者:jf_75140285 2024-08-15 14:23 次阅读

先点赞再看,养成好习惯

是极致魅惑、洒脱自由的 Java heap space

是知性柔情、温婉大气的 GC overhead limit exceeded

是纯真无邪、活泼可爱的 Metaspace

如果以上不是你的菜,那还有……

刁蛮任性,无迹可寻的 CodeCache

性感火辣、心思细腻的 Direct Memory

高贵冷艳,独爱你一人的 OOM Killer

总有一款,能让你钟情!BUG 选择权,现在交由你手!

Java heap space

这是最常见的一个 OOM 问题了,谁还没经历过一个 Heap OOM呢?

当堆内存被塞满之后,一边 GC 无法及时回收,一边又在继续创建新对象,Allocator 无法分配新的内存之后,就会送一个 OOM 的错误:

java.lang.OutOfMemoryError: Java heap space

分析解决起来无非是那几步:

dump 堆内存

通过 MAT、YourKit、JProfiler 、IDEA Profiler 等一系列工具分析dump文件

找到占用内存最多、最大的对象,看看是哪个小可爱干的

分析代码,尝试优化代码、减少对象创建

增加 JVM 堆内存、限制请求数、线程数、增加节点数量等

常见类库使用误区

尤其是一些工具库,尽可能的避免每次新建对象,从而节省内存提升性能。

大多数主流的类库,入口类都保证了单例线程安全,全局维护一份即可

举一些常见的错误使用例子:

Apache HttpClient

CloseableHttpClient ,这玩意相当于一个“浏览器进程”了,背后有连接池连接复用,一堆机制的辅助类,如果每次都 new 一个,不仅速度慢,而且浪费了大量资源。

比较正常的做法是,全局维护一个(或者根据业务场景分组,每组一个)实例,服务启动时创建,服务关闭时销毁:

CloseableHttpClient httpClient = HttpClients.custom()
                .setMaxConnPerRoute(maxConnPerRoute)
                .setMaxConnTotal(maxConnTotal)
                /// ...
                                 .build();

Gson

毕竟是 Google 的项目,入口类自然也是实现了线程安全,全局维护一份 Gson 实例即可

Jackson

Jackson 作为 Spring MVC 默认的 JSON 处理库,功能强大、用户众多,xml/json/yaml/properties/csv 各种主流格式都支持,单例线程安全自然也是 ok 的,全局维护一份 ObjectMapper 即可。

GC overhead limit exceeded

这个错误比较有意思,上面的 Java heap space 是内存彻底满了之后,还在持续的创建新对象,此时服务会彻底假死,无法处理新的请求。

而这个错误,只是表示 GC 开销过大,Collector 花了大量的时间回收内存,但释放的堆内存却很小,并不代表服务死了

此时程序处于一种很微妙的状态:堆内存满了(或者达到回收阈值),不停的触发 GC 回收,但大多数对象都是可达的无法回收,同时 Mutator 还在低频率的创建新对象。

出现这个错误,一般都是流量较低的场景,有太多常驻的可达对象无法回收,但是吧,GC 后空闲的内存还可以满足服务的基本使用

不过此时,已经在频繁的老年代GC了,老年代又大对象又多、在现有的回收算法下,GC 效率非常低并切资源占用巨大,甚至会出现把 CPU 打满的情况。

出现这个错误的时候,从监控角度看起来可能是这个样子:

请求量可能并不大

不停 GC,并切暂停时间很长

时不时的还有新的请求,但响应时间很高

CPU 利用率很高

毕竟还是堆内存的问题,排查思路和上面的 Java heap space 没什么区别。

Metaspace/PermGen

Metaspace 区域里,最主要的就是 Class 的元数据了,ClassLoader 加在的数据,都会存储在这里。

MetaSpace 初始值很小,默认是没有上限的。当利用率超过40%(默认值 MinMetaspaceFreeRatio)会进行扩容,每次扩容一点点,扩容也不会直接 FullGC。

比较推荐的做法,是不给初始值,但限制最大值:

-XX:MaxMetaspaceSize=

不过还是得小心,这玩意满了后果很严重,轻则 Full GC,重则 OOM:

java.lang.OutOfMemoryError: Metaspace

排查 MetaSpace 的问题,主要思路还是追踪 Class Load数据,比较主流的做法是:

通过 Arthas 之类的工具,查看 ClassLoader、loadClassess 的数据,分析数量较多的 ClassLoader 或者 Class

打印每个 class 的加载日志:-XX:+TraceClassLoading -XX:+TraceClassUnloading

下面介绍几个常见的,可能导致 MetaSpace 增长的场景:

反射使用不当

JAVA 里的反射,性能是非常低的,以反射的对象必须得缓存起来。尤其是这个Method对象,如果在并发的场景下,每次都获取新的 Method,然后 invoke 的话,用不了多久 MetaSpace 就给你打爆!

简单的说,并发场景下,Method.invoke 会重复的动态创建 class,从而导致 MetaSpace 区域增长,具体分析可以参考笨神的文章《从一起GC血案谈到反射原理》。

用反射时,尽可能的用成熟的工具类,Spring的、Apache的都可以。它们都内置了reflection相关对象的缓存,功能又全性能又好,足以解决日常的使用需求。

一些 Agent 的 bug

一些 Java Agent,静态的和运行时注入的都算。基于 Instrumentation 这套 API 做了各种增强,一会 load 一会 redefine 一会remove的,如果不小心出现 BUG,也很容易生成大量动态的 class,从而导致 metaspace 打满。

动态代理问题

像 Spring 的 AOP ,也是基于动态代理实现的,不管是 CgLib 还是 JDK Proxy,不管是 ASM 还是 ByteBuddy。最终的结果都逃不开动态创建、加载 Class,有这两个操作,那 Metaspace 必定受影响。

Spring 的 Bean 默认是 singleton 的,如果配置为 prototype,那么每次 getBean 就会创建新的代理对象,重新生成动态的 class、重新 define,MetaSpace 自然越来越大。

Code Cache

Code Cache 区域,存储的是 JIT 编译后的热点代码缓存(注意,编译过程中使用的内存不属于 Code cache),也属于 non heap 。

如果 Code cache 满了,你可能会看到这么一条日志:

Server VM warning: CodeCache is full. Compiler has been disabled.

此时 JVM 会禁用 JIT 编译,你的服务也会开始变慢。

Code Cache 的上限默认比较低,一般是240MB/128MB,不同平台可能有所区别。

可以通过参数来调整 Code Cache 的上限:

-XX:ReservedCodeCacheSize=

只要尽量避免过大的Class、Method ,一般也不太会出现这个区域被打满的问题,默认的 240MB/128MB 也足够了

Direct Memory

Direct Memory 区域,一般称之为直接内存,很多涉及到 磁盘I/O ,Socket I/O 的场景,为了“Zero Copy”提升性能都会使用 Direct Memory。

就比如 Netty ,它真的是把 Direct Memory 玩出了花(有空写一篇 Netty 内存管理分析)……

使用 Direct Memory时,相当于直接绕过 JVM 内存管理,调用 malloc() 函数,体验手动管理内存的乐趣~

不过吧,这玩意使用比较危险,一般都配合 Unsafe 操作,一个不小心地址读写的地址错误,就能得到一个 JVM 给你的惊喜:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffdbd5d19b4, pid=1208, tid=0x0000000000002ee0
#
# JRE version: Java(TM) SE Runtime Environment (8.0_301-b09) (build 1.8.0_301-b09)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.301-b09 mixed mode windows-amd64 compressed oops)  
# Problematic frame:
# C  [msvcr100.dll+0x119b4]
# 
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

更多的解释,可以参考我这篇《Java中的Heap Buffer与Direct Buffer

这个 Direct Memory 区域,默认是无上限的,但为了防止被 OS Kill,还是会限制一下,给个256MB或者更小的值,防止内存无限增长:

-XX:MaxDirectMemorySize=

如果 Direct Memory 达到 MaxDirectMemorySize 并且无法释放时,就会得到一个 OOM错误:

java.lang.OutOfMemoryError: Direct buffer memory

Linux OOM Killer

跳出 JVM 内存管理之后,当 OS 内存耗尽时,Linux 会选择内存占用最多,优先级最低或者最不重要的进程杀死。

一般在容器里,主要的进程就是肯定是我们的 JVM ,一旦内存满,第一个杀的就是它,而且还是 kill -TERM (-9)信号,打你一个猝不及防。

如果 JVM 内存参数配置合理,远低于容器内存限制,还是出现了 OOM Killer 的话,那么恭喜你,大概率是有什么 Native 内存泄漏。

这部分内存,JVM 它还管不了。

除了 JVM 内部的 Native 泄漏 BUG 这种小概率事件外,大概率是你引用的第三方库导致的。

这类问题排查起来非常麻烦,毕竟在 JVM 之外,只能靠一些原生的工具去分析。

而且吧,这种动不动就要 root 权限的工具,可是得领导审批申请权限的……排查成本真的很高

排查 Native 内存的基本的思路是:

pmap 查看内存地址映射,定位可疑内存块、分析内存块数据

strace 手动追踪进程系统调用,分析内存分配的系统调用链路

更换jemalloc/tcmalloc之类的内存分配器(或者 async-profiler有个支持native 分析的分支)追踪malloc的调用链路

目前最常见的 Native 内存泄漏场景,是 JDK 的 Inflater/Deflater 这俩卧龙凤雏,功能是提供 GZIP 的压缩、解压,在默认 glibc 的 malloc 实现下,很容易出现“内存泄漏”。如果出现 Native 内存泄漏,可以先看看应用里有没有 GZIP 相关操作,说不定有惊喜。


好了,各类风格的 OOM 都感受完了,到底哪一个更能打动你呢?

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2957

    浏览量

    104539
  • JVM
    JVM
    +关注

    关注

    0

    文章

    157

    浏览量

    12206
收藏 人收藏

    评论

    相关推荐

    别动,人类已经超级乐视包围了

    漂着乐视云……人类已经超级乐视包围了。##乐视打智能手机这张牌令 “平台+内容+终端+应用”的生态模式看起来更加完备。
    发表于 04-15 09:26 1413次阅读

    基于 GPU 渲染的高性能空间包围计算

    空间包围检测在计算机图形学、虚拟仿真、工业生产等有着广泛的应用。
    的头像 发表于 02-18 10:47 652次阅读
    基于 GPU 渲染的高性能空间<b class='flag-5'>包围</b>计算

    Matlab Out of memory问题总结(1)

    首先,要声明,matlab自带的Help才是最权威的Matlab学习资料,如果有时间好好学习一下或是可以高效的使用的话,一定受益匪浅!比如说像Out of Memory这个问题,最开始
    发表于 02-24 15:26

    Matlab Out of memory问题总结(2)

    arrayY1000x10004004000double array (sparse)5.使用pack命令当内存分为很多碎片以后,其实本身可能有很大的空间,只是没有作构的连续空间即大的Block而已。如果此时Out
    发表于 02-24 15:27

    vivado建立AD9361配置工程总是弹出out of memory错误

    运行system_project.tcl之后一段时间总是弹出out of memory 错误。但是改用vivado2013.4版本使用相应的hdl_2014_r1则不存在问题,请问vivado2014.2遇到的out of
    发表于 10-08 16:37

    matlab打开1G以上的数据出现out of memory error

    用matlab打开1G以上的数据出现out of memory error谁遇到过这个情况么 有什么有效的解决办法么
    发表于 04-17 06:36

    C6748_NandWrite.out文件报错

    verify target memory and memory map。看了下,0xC0000000是DDR2的地址。想问下C6748_NandWrite.
    发表于 05-29 15:38

    PSoC Creator怎么进行嵌入式设计?

    嵌入式系统是计算设备硬件中嵌入软件作为其核心组件的应用。我们身边现在已经嵌入式系统包围了,这些产品能为我们的生活带来各种方便乃至奢华的功能,包括移动手持设备、洗衣机、微波炉、ATM 机、空调等等。由于某些特定的应用要求,工程师必须以不同于其它设计类型的特定方法进行嵌入式
    发表于 04-13 07:04

    运行时出现out of memory是堆配置原因吗

    [C674X_0] ti.sy***ios.heaps.HeapMem: line 307: out of memory: handle=0xc01d7118, size
    发表于 04-22 14:15

    大佬们,Error (114016): Out of memory in module quartus_map.exe (20434 megabytes used)怎么解决

    Error (114016): Out of memory in module quartus_map.exe (20434 megabytes used)Error (293007
    发表于 06-01 07:31

    pads 9.5 / VX2.11 Out of memory

    在win10/win11下使用PADS layout时,报错‘’Out of memory‘’,或者报错‘’数据库严重错误编号 2010‘’已经尝试过:1.加大内存条内存,无法解决2.加大虚拟内存
    发表于 03-25 18:58

    用VScode将kmodel和代码制作成的bin文件烧入K210开发板中出现“iomem malloc out of memory”是什么情况?

    用VScode将kmodel和代码制作成的bin文件烧入K210开发板中出现“iomem malloc out of memory”是什么情况?
    发表于 09-13 06:35

    PCB设计:盘中孔工艺,到底有多大价值?

    不知道大家在画PCB的时候会不会遇到这样的情况:芯片的引脚太密,某个引脚想要走线出去但是完全包围了,尤其是在BGA封装的芯片中。例如下图中的U1_B7引脚就没有办法再走线出去,四周都被包围了
    发表于 10-24 11:25 2223次阅读

    盘中孔工艺有多大价值?先前为什么在市场上没有普及呢?

    不知道大家在画PCB的时候会不会遇到这样的情况:芯片的引脚太密,某个引脚想要走线出去但是完全包围了,尤其是在BGA封装的芯片中。例如下图中的U1_B7引脚就没有办法在走线出去,四周都被包围了
    的头像 发表于 11-15 09:47 1645次阅读

    宏景智驾亮相WNAT-CES展:完蛋智驾友商包围了

    11月10日-12日,2023年世界新汽车技术合作生态展(WNAT-CES)在江苏苏州昆山国际会展中心隆重举办,宏景智驾携旗下系列产品亮相本次展会。 此次宏景智驾展出的产品包括支持ADAS功能的智能摄像头产品以及支持L2+级智能驾驶功能实现的系列域控制器产品,目前这些产品皆已在国内主流车企的畅销车型上实现量产交付。 作为全栈智能驾驶研发公司,在软件层面,宏景智驾在行车、泊车以及行泊一体系统开发领域也有深厚的积累。此次展会也是集中展示了宏
    的头像 发表于 11-14 15:10 542次阅读
    宏景智驾亮相WNAT-CES展:<b class='flag-5'>完蛋</b>!<b class='flag-5'>我</b><b class='flag-5'>被</b>智驾友商<b class='flag-5'>包围了</b>!