内存溢出OOM如何定位?常见原因及解决措施梳理总结

检测维修 0 145

最近有人询问怎样找出内存溢出内存泄漏的问题,我将以前了解的相关要点整理归纳如下:

内存溢出OOM 定义

内存耗尽,即所谓的Out Of Memory,是应用系统遇到的一种状况,表现为存在无法释放的内存空间,或者内存消耗量超出了系统所能提供的最大值,导致程序运行时所需内存超过了可用内存总量。

补充:

内存溢出的常见原因及措施

常见原因

分配量不足,系统或JVM提供的内存无法满足程序运行所需,资源欠缺。

程序占用内存量很大,已经超出系统或JVM所能提供的范围。

内存占用完毕后没有立刻归还,造成内存资源积压,最后导致内存空间耗尽。

为了解决内存溢出问题,可以采取以下措施:

扩充内存容量,可以借助扩充系统内存,或者调节JVM内存堆的尺寸,以此获得更充足的内存空间。

改进程序:仔细检查并完善代码,保证及时清除无用对象和资源,防止内存溢出。

要节省内存空间,需精心挑选存储和处理数据的结构,确保结构匹配数据特性。

监测内存消耗状况:借助管理软件周期性审视软件的内存占用情形,快速察觉并处置内存损耗及内存超载状况。

常见的OOM问题定位分析

上述偏于理论了,来看下实战操作:本文适用 Linux系统

借助系统命令查看系统负载

运用指令例如top能够察看系统运行压力,涵盖内存运用状况、程序占用资源情形等。此类资讯能够协助您掌握系统的综合运作状态,并且可以判断有无其他程序耗费了诸多内存。

命令行:直接敲命令【】内的命令

能够了解到整个设备的中央处理器和内存使用状况,同时也能明确哪个程序占用了最多的系统资源

使用命令ps -aux并配合grep redis功能,可以查询到当前设备上所有涉及Redis的运行进程详情

ps辅助aux命令筛选java关键词,能够列出所有java程序的运行标识,这个功能跟jps指令作用相同,假如当前查询的目标是运行编号为7545的进程

【top -Hp 7545】 ===》需要观察 这个任务内部各个工作单元的运行状况,同时也要弄清楚 哪个工作单元消耗了较多的计算资源和内存资源. 如果需要的话 会使用【pstree -s #PID】借助树形图来弄明白 这个任务与其子任务之间的层级关系

【查看系统内存信息 -g 】 ===》可以了解整个设备的内存使用状况,以及内存还剩下多少

借助系统命令查看系统日志

通过以下指令,可以检索内存耗尽的相关资讯,涵盖异常出现时的环境状况以及潜在诱因,例如进程崩溃的场景和可能触发因素。

使用特定命令,可以查看到系统日志文件的末尾一千行内容,该命令针对的是位于指定路径下的日志文件

【 dmesg 】// 查看内核日志

通过遍历 /var/log 目录下的所有文件,并筛选出包含 error 字样的内容,可以找到相关的错误信息记录

补充:这些命令 一般 需要懂系统内核

内存泄漏分析工具_OOM内存溢出定位_linux下内存泄露检测工具介绍

内存溢出时,有时会生成coreDump文件,通过分析这个文件,可以了解一些情况。不过通常,正规的公司会对生产环境禁用core文件生成。在这种情况下,在开发新版本时,可以设定自定义的信号处理函数,用来记录崩溃瞬间对应的函数调用堆栈信息,以此取代coreDump的默认功能。

查看应用程序日志

检查软件的记录文档,寻找内存耗尽的警示内容。这些内容一般包含有关内存溢出异常的详尽资料,例如故障的种类、故障产生的地点等。

这项工作要求掌握编程知识,并且运用所记录的数据,分析当时的系统流程以及各个堆栈和线程的活动情况。同时参考故事场景,就能尽可能模拟出问题发生时的状况,实现"精准调整",也为后续的验证工作提供便利。

使用工具检测内存溢出

利用诸如valgrind、memcheck这类专用软件,能够有效发现程序在运行时存在的内存异常问题。

有关工具使用,可以度娘一把。

这种方法存在一定局限,对于某些大企业生产环境中的日志文件、程序崩溃报告等受权限限制的文件,往往难以直接访问。这种情况下,需要借助平台提供的工具进行追踪,而要做到这一点,就必须对业务逻辑、代码实现乃至服务器硬件参数有深入的了解,这样才能更高效地找出问题根源。

在我的工作经历里,能够根据具体发生的时间节点以及当时的版本信息,对调用链、机器状态等众多方面进行剖析,在需要时或许会借助 git diff 来对比版本之间的差异。

内存泄漏Memory Leak 定义

内存泄漏,即动态分配的堆内存因故未被程序释放或无法释放,造成系统内存的浪费,导致程序运行迟缓,甚至引发系统崩溃等严重情况。也可以看作是程序在执行过程中,未能及时释放那些不再使用的内存空间,造成可用内存量逐步下降。

内存泄漏与内存溢出区别

内存溢出和内存泄漏是两个截然不同的概念。内存泄漏意味着程序在执行过程中没有释放那些已经不再使用的内存空间,造成可用内存量持续下降。只要程序不断运行并且内存泄漏问题没有得到解决,总有一天会引发内存溢出。而内存溢出是指应用程序申请的内存数量,已经超出了系统或者Java虚拟机所能分配的最大内存限制。程序运行可能就此中断,系统会弹出内存不足的提示,甚至会造成程序终止或设备完全僵化。

内测泄漏常见错误

内存泄漏的常见错误可以归纳为以下几个方面:

内存分配后未及时回收是造成内存溢出的主要问题。开发者在C++中使用new或在C中使用malloc为对象或数据结构在堆上申请内存时,必须在不再使用这些内存后,通过delete或free函数手动将其释放。若忽略这一步骤,就会引发内存泄漏现象。

指针可以再次被指定新地址,在特定情形下,编程人员可能将指针指向不同位置,使得原先关联的存储空间变成无法触及的“废弃区域”。比如,当先为指针p分配了一段内存,随后又将p改指向另一块新开辟的存储范围,但先前p所关联的内存没有被回收,就会造成内存资源浪费问题。

内存管理不当。当处置含有指向堆区分配空间的指针的结构体或复杂构造体时,若仅回收了主体内存却未逐一清理内部指针指向的动态资源,会造成内存泄漏现象。

函数返回指向动态内存的指针或引用时,若在函数外未妥善处置,比如未释放或未重新指定,就会造成内存泄漏。

对象引用进入缓存后,若缓存缺乏妥善维护,比如缺少合理的清理机制或容量控制,便可能造成内存溢出问题。对象一旦存入缓存,往往会在内存中停留很长时间,即便它们已经不再被使用。

程序出现意外状况时,常会忽略已分配内存的回收步骤,这种情况多见于异常流程中的代码缺乏必要的错误应对或资源整理措施。

对象生存期控制存在疏漏,在运用智能指针(例如C++里的std::unique_ptr、std::shared_ptr)或具备自动内存回收特性的编程语言中,若未能妥善处理对象的存在周期(比如形成了相互引用的闭环,或不当移除了对象的所有权),同样会造成内存资源无法释放的问题。

内存泄漏常见定位

这些方法在部分情形中,同样能够帮助发现内存泄漏的情况。

使用工具检测内存泄漏

为了防止内存资源耗尽,并找出内存使用中的问题,程序员能够借助特定的软件来观察内存运作状态,并找出可能的内存泄漏情况,这些软件包括Valgrind、VisualVM、MAT等,它们能够帮助定位问题所在,Valgrind在检测内存泄漏方面非常出色,不过使用它需要事先了解其功能。

其他实战补充

针对内存型程序,比如Redis,处理这类故障时往往要依靠手动排查,例如输出数据,通过排序检查内存何处存在异常,对可读信息进行研判和推测,(通过设置监测点收集更多数据),尝试调整程序代码,再次进行验证,这种不断循环直到问题彻底解决,才算得上是彻底查明了原因。

此外,优秀的代码规范、恰当的意外情况应对和资源回收机制对于降低内存占用问题很有帮助。例如:在通常预料到异常发生时,返回数据之前,应该先解除占用。

另外,我们过去有一个项目,由于“紧急”(业内都明白),某日突然出现内存告警,这才发觉那个组件的内存一直在增加。运维人员稍作排查,重启了该组件,并将情况通报给了研发部门。随后,我编写了一个轻便的shell脚本(用于采集内存状况),部署到线上,设置为定时任务(每小时执行一次)。经过七天监测,依据汇总的资料状况,包括整体增值幅度、内存增量规律等,同时附带CPU运用率信息,与技术开发团队进行沟通。【说明:在大型企业的运作场景中,并非所有应用软件都能部署,这关乎到“符合规定”的考量,必须以最少的“资源消耗”途径,获取最关键的】。

相关推荐: