服务器Docker OOM RSS高问题排查思路

news2024/11/22 11:06:09

优质博文:IT-BLOG-CN

防走弯路为防止走弯路,强烈建议先仔细阅读以下加粗内容:
如果你的应用是因为公司最近降成本调小实例物理内存才出现docker oom,而之前从来没有出现过,那么大概率是堆内存太大导致,这种情况尤其在实例物理内存<=4G的情况下多发。所以如果你的case满足以下场景,基本是堆内存设置不合理导致:
【1】先看看你的应用heap实机用量,然后调小xmx到一个比较合理的数值,这里一定要自己定义xmx,不要用ops默认的计算值,因为那个计算值会把xmx设置为物理内存的3/4,对于小内存来说,这太大了;
【2】很多应用为了避免堆内存扩容导致性能下降,会将xmsxms设置成一样大,也会加剧小物理内存实例的docker oom。所以建议小内存实例把xms设置为物理内存的1/21/3
【3】如果有的groupoom(比如ALI集群有oom),有的一直没有,那么基本不是内存泄露导致,因为如果有内存泄露,那么任何集群都会出现oom。猜测这种情况因为实例底层参数差异导致(暂无法求证),建议你把oom集群堆内存调小256m看看oom是否得到解决;
【4】如果不满足上述两种情形,那就继续往下看吧;

一、前言

Java进程使用的内存分为3部分:堆内存、虚拟机所使用的内存(一般叫Native Memory)、堆外内存(off-heap)组成。
【1】堆heap内存也就是你jvm参数里面设置的xmxxms所指定的大小。如果你的工程里面的extraenv.sh没有指定xms/xms,那么ops会默认给你指定成物理内存的3/4。比如物理内存4G,那么堆内存会是3072m,这其实有点太大了;
【2】Native memory:虚拟机使用的内存,分为很多细分的区域,比如classgcthreadcodeinternal等;

名称作用描述
Java Heap你所使用的堆内存
Class元数据区,存储class信息,lambda表达式编译成的临时类也存放在这里面,可以通过-XX:MaxMetaspaceSize=256m限制大小
Thread线程使用的内存区域, 用量可以简单的换算关系为线程数*xss。默认xss=1024k。如果你有1000个线程,那么Thread区可以占到1G。所以一般我们会设置xss=256k
CodeJIT编译后的机器码所使用的区域
GC垃圾回收器使用的内存区域,比如card table、RSet等。性能越好的垃圾回收器所占用的内存越大,另外如果你使用G1同时内存缓存了太多数据,那么G1也会占用很多的内存,因为它会把对象之间的引用关系放在RSet里面。
CompilerJIT编译将class编译成机器码时所使用的临时区域
Internal包含命令行解析器使用的内存、JVMTI、PerfData 以及 Unsafe 分配的内存等
Other其他没有被覆盖到的区域
SymbolSymbol 为 JVM 中的符号表所使用的内存,HotSpot中符号表主要有两种:SymbolTable 与 StringTable(字符串常量池)
Native Memory TrackingNMT开启是有性能损耗的,这块区域就是JVM为Native Memory Tracking开辟的内存区域
Arena ChunkJVM 分配的一些 Chunk(内存块),当退出作用域或离开代码区域时,内存将从这些 Chunk 中释放出来。然后这些 Chunk 就可以在其他子系统中重用. 需要注意的是,此时统计的 Arena 与 Chunk ,是 HotSpot 自己定义的 Arena、Chunk,而不是 Glibc 中相关的 Arena 与 Chunk 的概念
LoggingJVM logging使用内存
ArgumentsMemory for arguments
ModuleMemory used by modules

服务器RSS过高会导致被拉出或者OOM,虽然各个公司现有的高可用机制能自动检测并通过进程重启的方式恢复服务,但我们需要知道RSS过高是什么原因导致的。本文会梳理一下RSS过高的排查套路,避免你走弯路。

首先,我们需要知道的是,Java进程消耗的内存绝不仅仅是你设置的Xmx这么简单,Java进程占用的内存分为3部分:堆内存、JVM自身消耗的内存、堆外内存。所以,后续的排查思路我们也是按照上面的3个方面来顺序展开。下图是各种JVM垃圾回收器消耗内存的比例,注意这部分内存是堆内存之外的:
在这里插入图片描述

实践证明,G1内存开销甚至能占到堆内存的20%,恐怖吧,惊喜不……

1 确认堆内存是否太大
首先要确认一下Java应用的堆内存是否太大,这个可以通过hickwall的appid docker linux tomcat多机模板 VM 查看。因为JVM自身也会消耗一些内存,所以你至少需要预留出部分内存存给JVM使用。如果应用涉及较多的网络通信,那还需要预留一些内存给堆外使用,所以一般来说你的堆内存最多为服务器物理内存减去1.2G,如4G服务器,那么堆内存最大为2.8G;(之前为3G,但就目前的趋势看,jvm自己用的内存也越来越多,所以这里调整成2.8G。当然这里是经验值,还是要结合你的应用所使用的堆内存决定)。
如果确认你的堆内存使用过多的话,那么问题相对简单了,我们可以通过dump堆内存,使用mat分析基本能定位到问题。这方面的问题很多,大家可以自行搜索。
2 确认是否DirectByteBuffer用量太大
我们知道,很多有网络交互的组件底层是基于netty或者nio的,而nio为了提高性能,会申请一部分堆外内存,有的是基于DirectByteBuffer申请的,如果网络交互频繁而且报文尺寸大,这部分内存的占用还是比较可观的,比如下面这个应用,DirectByteBuffer用量都能达到700m。

在这里插入图片描述

需要注意的是:Java对于DirectByteBuffer的用量是没有做限制的,也就是它可以申请物理内存那么多的用量。所以如果你的DirectByteBuffer用量比较多,可以通过在jvm参数中设置-XX:MaxDirectMemorySize这个参数控制一下。在DirectByteBuffer用量超过你设置的大小时,系统会触发一次System.gc()(未必是FGC)。
3 确认是否存在大量ARENA区
如果堆内存不大,那么继续排查非堆内存。首先我们去看一下ARENA区。在高并发的应用中,往往ARENA区占用的内存会比较多。至于ARENA是什么东东,可以读一下这篇文章:https://blog.csdn.net/maokelong95/article/details/51989081
执行如下命令:

sudo -u deploy pmap -x <pid>|sort -gr -k2 |less 

如果存在大量大小为6553665404的内存区域,则说明ARENA区域占用了太多的内存,如下图所示:
在这里插入图片描述

这种情况下,有2个选择:内存分配器换成jemalloc,详情见:jemalloc 服务 ( http://conf.ctripcorp.com/pages/viewpage.action?pageId=1131500186 )粗暴的办法是修改环境变量的值,在extraenv.sh中添加这么一行:export MALLOC_ARENA_MAX=1需要注意的是,上述的数值只能是1,其他大于1的数值经实践证明是无法控制ARENA数量的。4 确认Native Memory开销过大如果前面2个步骤看到的内存开销都不大,还有很多内存区域你不知道消耗在哪里了,那么我们开始第三步:开启Native Memory Tracking。前面我们说过,Java应用的执行,JVM自身也需要消耗一些内存的,通过开启Native Memory Tracking,我们就能知道JVM自身消耗了多少内存。请不要迷信vi里面的非堆内存消耗,那是不准确的……书归正传,通过修改/opt/tomcat/bin/setenv.sh中的JVM参数并重启Java进程开启:

-XX:NativeMemoryTracking=detail 

进程重启后,可以通过以下命令查看NativeMemory的占用情况:

sudo -Esu deploy /usr/java/default/bin/jcmd <pid> VM.native_memory summary 

你会看到以下类似的执行结果:
在这里插入图片描述

通过上图,你可以看到JVM各个区域所使用的内存大小,主要包含了Java Heap、Class、Thread、Code、GC、Compiler、Internal、Other、Symbol、Native Memory Tracking、Arena Chunk这几部分。
需要注意的是Class、Thread、GC几个区域的大小。
上面的图片是27G的堆内存,使用G1回收器,你能看到GC区居然占用了3.8G的内存。
针对上面的各个区域大小做加法,看一下是否接近于RSS的大小,如果是,恭喜你可以到此结束了。后续你需要做的就是针对内存占用比较大的JVM区去做优化,这里就不详细介绍了。
如果不是,很遗憾,你进入到了最难啃的环节,继续往下看吧。

需要注意的是,开启NativeMemoryTracking会造成5%的性能下降,用完记得关闭。
可以通过以下命令临时关闭:

sudo -Esu deploy /usr/java/default/bin/jcmd <pid> VM.native_memory stop 

或者修改/opt/tomcat/bin/setenv.sh中的JVM参数并重启永久关闭。

如果你嫌上面的文章安装配置比较麻烦,你也可以用我的jtoolkit去排查,安装命令很简单:

curl -L http://devresources.flight.ctripcorp.com/jtoolkit/shells/install.sh|bash 

安装完毕,根据提示去使用就可以了,希望通过上面的介绍,能解决你的问题。

如果很不幸你的问题还没有得到解决的话,那么抱歉,这超出了我的认知了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2244626.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu Linux使用前准备动作_使用root登录图形化界面

Ubuntu默认是不允许使用 root 登录图形化界面的。这是出于安全考虑的设置。但如果有需要&#xff0c;可以通过以下步骤来实现使用 root 登录&#xff1a; 1、设置 root 密码 打开终端&#xff0c;使用当前的管理员账户登录系统。在终端中输入命令sudo passwd root&#xff0c…

core 不可变类型 线程安全 record

当一个类型的对象在创建时被指定状态后&#xff0c;就不会再变化的对象&#xff0c;我们称之为不可变类型。这种类型是线程安全的&#xff0c;不需要进行线程同步&#xff0c;非常适合并行计算的数据共享。它减少了更新对象会引起各种bug的风险&#xff0c;更为安全。 System.D…

Python-简单病毒程序合集(一)

前言&#xff1a;简单又有趣的Python恶搞代码&#xff0c;往往能给我们枯燥无味的生活带来一点乐趣&#xff0c;激发我们对编程的最原始的热爱。那么话不多说&#xff0c;我们直接开始今天的编程之路。 编程思路&#xff1a;本次我们将会用到os,paltform,threading,ctypes,sys,…

ForEach刷新UI机制

官网地址&#xff1a;ForEach 在ArkUI中&#xff0c;提供了ForEach循环语句&#xff0c;用来初始化一个列表数据&#xff0c;我们知道&#xff0c;当ForEach中的数组发生变化时&#xff0c;会引起UI的刷新&#xff0c;但是究竟如何变化&#xff0c;会引起UI怎样的刷新&#xf…

如何解决pdf.js跨域从url动态加载pdf文档

摘要 当我们想用PDF.js从URL加载文档时&#xff0c;将会因遇到跨域问题而中断&#xff0c;且是因为会触发了PDF.js和浏览器的双重CORS block&#xff0c;这篇文章将会介绍&#xff1a;①如何禁用pdf.js的跨域&#xff1f;②如何绕过浏览器的CORS加载URL文件&#xff1f;②如何使…

Three.js 相机控制器Controls

在 3D 场景中&#xff0c;摄像机的控制尤为重要&#xff0c;因为它决定了用户如何观察和与场景互动。Three.js 提供了多种相机控制器&#xff0c;最常用的有 OrbitControls、TrackballControls、FlyControls 和 FirstPersonControls。OrbitControls 适合用于查看和检查 3D 模型…

C++小白实习日记——Day 5 gitee怎么删文件,测试文件怎么写循环

昨晚一直内耗&#xff0c;一个程序写了三天写不出来&#xff0c;主要是耗时太多了&#xff0c;老板一直不满意。想在VScode上跑一下&#xff0c;昨晚一直报错。今天来公司重新搞了一下&#xff0c; 主要工作有&#xff1a; 1&#xff0c;读取当前时间用tscns 2&#xff0c;输…

【从零开始的LeetCode-算法】3301. 高度互不相同的最大塔高和

给你一个数组 maximumHeight &#xff0c;其中 maximumHeight[i] 表示第 i 座塔可以达到的 最大 高度。 你的任务是给每一座塔分别设置一个高度&#xff0c;使得&#xff1a; 第 i 座塔的高度是一个正整数&#xff0c;且不超过 maximumHeight[i] 。所有塔的高度互不相同。 请…

利用uniapp开发鸿蒙:运行到鸿蒙模拟器—踩坑合集

从uniapp运行到鸿蒙模拟器上这一步&#xff0c;就有非常多的坑&#xff0c;一些常见的坑&#xff0c;官网都有介绍&#xff0c;就不再拿出来了&#xff0c;这里记录一下官网未记录的大坑 1.运行路径从hbuilderx启动鸿蒙模拟器 解决方法&#xff1a; Windows系统&#xff0c;官…

基于UDP和TCP实现回显服务器

目录 一. UDP 回显服务器 1. UDP Echo Server 2. UDP Echo Client 二. TCP 回显服务器 1. TCP Echo Server 2. TCP Echo Client 回显服务器 (Echo Server) 就是客户端发送什么样的请求, 服务器就返回什么样的响应, 没有任何的计算和处理逻辑. 一. UDP 回显服务器 1. UD…

游戏引擎学习第17天

视频参考:https://www.bilibili.com/video/BV1LPUpYJEXE/ 回顾上一天的内容 1. 整体目标&#xff1a; 处理键盘输入&#xff1a;将键盘输入的处理逻辑从平台特定的代码中分离出来&#xff0c;放入更独立的函数中以便管理。优化消息循环&#xff1a;确保消息循环能够有效处理 …

Ubuntu常见命令

关于export LD_LIBRARY_PATHcmake默认地址CMakelists.txt知识扩充/home&#xff1a;挂载新磁盘到 /home 子目录 关于export LD_LIBRARY_PATH 程序运行时默认的依赖库的位置包括lib, /usr/lib ,/usr/local/lib 通过命令export LD_LIBRARY_PATHdesired_path:$LD_LIBRARY_PATH追加…

Linux驱动开发快速入门——字符设备驱动(直接操作寄存器设备树版)

Linux驱动开发快速入门——字符设备驱动 前言 笔者使用开发板型号&#xff1a;正点原子的IMX6ULL-alpha开发板。ubuntu版本为&#xff1a;20.04。写此文也是以备忘为目的。 字符设备驱动 本小结将以直接操作寄存器的方式控制一个LED灯&#xff0c;可以通过read系统调用可以…

论文阅读 SeedEdit: Align Image Re-Generation to Image Editing

目录 摘要 1 INTRODUCTION 2 SEEDEDIT 2.1 T2I MODEL FOR EDITING DATA GENERATION 2.2 CAUSAL DIFFUSION MODEL WITH IMAGE INPUT 2.3 ITERATIVE ALIGNMENT 3 EXPERIMENTS 3.1 BENCHMARK AND METRICS 3.2 IMAGE EDITING COMPARISON 4 CONCLUSION 摘要 SeedEdit&…

代码随想录算法训练营day41|动态规划04

最后一块石头的重量|| 返回剩余最后一块石头石头最小的可能重量&#xff0c;那么就应该最后剩余的两块石头尽量都等于或接近总重量的一半&#xff0c;这样剩下的就是一半的质量 目标和 给定一个非负整数数组&#xff0c;a1, a2, …, an, 和一个目标数&#xff0c;S。现在你有…

【C++】绘制内存管理的地图

生活是属于每个人自己的感受&#xff0c;不属于任何人的看法。 前言 这是我自己学习C的第二篇博客总结。后期我会继续把C学习笔记开源至博客上。 上一期笔记是关于C的类与对象础知识&#xff0c;没看的同学可以过去看看&#xff1a; 【C】面向对象编程的艺术之旅-CSDN博客https…

【AI大模型引领变革】探索AI如何重塑软件开发流程与未来趋势

文章目录 每日一句正能量前言流程与模式介绍【传统软件开发 VS AI参与的软件开发】一、传统软件开发流程与模式二、AI参与的软件开发流程与模式三、AI带来的不同之处 结论 AI在软件开发流程中的优势、挑战及应对策略AI在软件开发流程中的优势面临的挑战及应对策略 结论 后记 每…

前端访问后端实现跨域

背景&#xff1a;前端在抖音里做了一个插件然后访问我们的后端。显然在抖音访问其他域名肯定会跨域。 解决办法&#xff1a; 1、使用比较简单的jsonp JSONP 优点&#xff1a;JSONP 是通过动态创建 <script> 标签的方式加载外部数据&#xff0c;属于跨域数据请求的一种…

《Vue零基础入门教程》第二课:搭建开发环境

往期内容&#xff1a; 《Vue零基础入门教程》第一课&#xff1a;Vue简介 1 搭建开发环境 Vue环境分为两种 不使用构建工具使用构建丁具 首先&#xff0c;我们会介绍 不使用构建工具 的环境,在组件化章节中介绍 使用构建工具 的方式 1) 初始化 使用如下指令初始化 npm i…

快速排序【hoare版】

目录 介绍 算法思路 函数实现 函数声明 确定基准值 创建新函数 创建循环找数据&#xff08;right&#xff0c;left&#xff09; 交换左右数据 交换条件设置 外部循坏条件设置 初步总结代码 循环条件完善 内层循环的完善 外层循环的完善 相遇值大于keyi 相遇值等于k…