Linux Core Dump 解析

简介: 通常,在日常的应用系统维护活动中,有这样一种场景:在某一特定的时间段或者流量高峰时刻,我们的应用程序突然无缘无故的挂掉,没有任何征兆(当然,可能更为细致的监控没有检测到),也没有任何应用层面的日志抛出,然而,业务已经开始保障(我c,怎么又不行了,某些所谓的 XX 开始叫了。。。),顿时,大伙一脸懵逼 。。。经过对所有可疑的文件依据时间段进行“查水表”,终于有所发现。

    通常,在日常的应用系统维护活动中,有这样一种场景:在某一特定的时间段或者流量高峰时刻,我们的应用程序突然无缘无故的挂掉,没有任何征兆(当然,可能更为细致的监控没有检测到),也没有任何应用层面的日志抛出,然而,业务已经开始保障(我艹,怎么又不行了,某些所谓的 XX 开始叫了。。。),顿时,大伙一脸懵逼 。。。经过对所有可疑的文件依据时间段进行“查水表”,终于有所发现。

    何为 “Core Dump” 文件 ?

    Core Dump 也称之为“核心转储”, 若当前操作系统开启了 core dump ,当程序运行过程中发生异常或接收到某些信号使得程序进程异常退出时, 由操作系统把程序当前的内存状况以及相关的进程状态信息存储在一个 Core 文件中, 即 Core Dump 。通常,Linux 中如果内存越界会收到 SIGSEGV 信号,然后就会进行 Core Dump 相关操作。

   在我们大部分人的认知中,潜意识地认为 Core Dump 是针对 Linux 内存快照。其实,从本质上来讲Core Dump 文件不仅仅包含内存信息,譬如,还有些关键的程序运行状态也会同时 Dump 下来,例如,寄存器信息(包括程序指针、栈指针等)、内存管理信息、相关处理器信息以及操作系统状态及相关信息。Core Dump 对于技术人员,尤其是运维、开发,对其诊断和调试程序是非常有帮助的,毕竟,对于有些程序错误是很难重现的,例如,指针异常,然而,借助于 Core Dump 文件我们可以再一次模拟、重现应用程序抛异常时的情景。

    为什么会发生Core Dump

    Linux 系统中在应用程序运行过程中经常会遇到程序突然崩溃,提示:Segmentation fault,这是因为应用程序收到了 SIGSEGV 信号。这个信号提示当进程发生了无效的存储访问,当接收到这个信号时,缺省动作是:终止w/core。终止w/core的含义是:在进程当前目录生成 Core文件,并将进程的内存映象复制到 Core 文件中,Core 文件的默认名称就是 “Core”。
   事实上,并不是只有 SIGSEGV 信号产生 CoreDump,还有下面一些信号也产生 CoreDump:SIGABRT(异常终止)、SIGBUS(硬件故障)、SIGEMT(硬件故障)、SIGFPE(算术异常)、SIGILL(非法硬件指令)、SIGIOT(硬件故障),SIGQUIT,SIGSYS(无效系统调用),SIGTRAP(硬件故障)等。

    “Core Dump” 文件场景 ?

    在基于 Linux 系统,应用程序发生异常时,会产生 Core Dump 文件记录,这些异常或多或少甚至几乎都与“内存”脱不了干系,总结起来主要涉及以下:

    1、堆栈溢出问题

   通常来讲,例如,分配大量局部变量、多重函数调用、较深的函数递归等等都会有可能导致堆栈溢出现象。

    2、多线程访问问题

   此处主要包含以下2种场景,共享资源互斥访问异常以及调用不可重入函数等。

    3、内存访问越界

   此处主要涉及应用程序资源申请超出动态(malloc/new)内存申请范围、数组下标越界、常见的字符串没有结束符,例如,一些函数依赖于字符串结束符,如 strcpy、strcmp、sprintf等等都有可能导致。

    4、非法指针的异常访问        

    如何配置开启 “Core Dump” 文件

   通常,在实际的业务场景中,如果没有进行 Core Dump 的相关设置,默认是不开启的。可以通过 ulimit -c 命令行参数查看是否开启。如果输出为 “0”,则表示没有开启,此时,需要执行 ulimit -c unlimited 命令行开启 Core Dump 功能。


[administrator@JavaLangOutOfMemory ~ ]% ulimit -c 
0


[administrator@JavaLangOutOfMemory ~ ]% ulimit -a
core file size          (blocks, -c) 1024
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 127470
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 127470
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

    如上述命令行结果所示:结果为 0,则表明当前所有程序异常崩溃不会生成 Core Dump 文件。具体的开启命令行操作参数如下所示:


[administrator@JavaLangOutOfMemory ~ ]% ulimit -c 1024  #开启生成 core 文件,文件大小限制在1024KB以内
[administrator@JavaLangOutOfMemory ~ ]% ulimit -c 
1024
[administrator@JavaLangOutOfMemory ~ ]% ulimit -c unlimited  #开启生成 core 文件,文件大小无限制


   
通常,在大多数环境下,在 Core 生成开启的情况下,Linux 的应用程序在异常崩溃时一定会产生 Core Dump 文件,当 Core Dump 文件超过限定的大小时,文件将不生成。使用 ulimit -c filesize命令,可以限制 Core 文件的大小(filesize 的单位为 kbyte)。若 ulimit -c unlimited,则表示 Core 文件 的大小不受限制。如果生成的信息超过此大小,将会被裁剪,最终生成一个不完整的 Core 文件。在调试此 Core 文件的时候,gdb 会提示错误。因此,若在 ulimit -c 1024 情况下异常崩溃没有生成 Core 文件,我们则可以通过 ulimit -c unlimited 命令行参数操作将 Core 的文件规定设置为无限制。

    针对 ulimit 命令,此处进行简要的解析。作为 Linux 操作系统中关键的命令行工具之一,其主要用来限制系统用户对 Shell 资源的访问。涉及以下各种类型的限制:所创建的内核文件的大小、进程数据块的大小、Shell 进程创建文件的大小、内存锁住的大小、常驻内存集的大小、打开文件描述符的数量、分配堆栈的大小、CPU 时间片、单个用户的最大线程数、Shell 进程所能使用的最大虚拟内存。除此之外,其也能够支持硬资源和软资源的限制。针对  ulimit 命令相关语法选项如下所示:


-a:显示目前资源限制的设定;
-c <core文件上限>:设定core文件的最大值,单位为区块;
-d <数据节区大小>:程序数据节区的最大值,单位为KB;
-f <文件大小>:shell所能建立的最大文件,单位为区块;
-H:设定资源的硬性限制,也就是管理员所设下的限制;
-m <内存大小>:指定可使用内存的上限,单位为KB;
-n <文件数目>:指定同一时间最多可开启的文件数;
-p <缓冲区大小>:指定管道缓冲区的大小,单位512字节;
-s <堆叠大小>:指定堆叠的上限,单位为KB;
-S:设定资源的弹性限制;
-t <CPU时间>:指定CPU使用时间的上限,单位为秒;
-u <程序数目>:用户最多可开启的程序数目;
-v <虚拟内存大小>:指定可使用的虚拟内存上限,单位为KB。

    通常,基于默认配置环境下,系统生成的 Core 文件是不带其它任何扩展名称,即往往会被命名为 core。同时,新的 core 文件生成将覆盖原来旧的 core文件 。因此,基于特定的场景,我们需要对 Core 文件的名称和生成路径进行相关的配置,以满足我们实际的问题排障需要,具体操作可参考如下所示:


[administrator@JavaLangOutOfMemory ~ ]% echo "1" > /proc/sys/kernel/core_uses_pid

    基于 /proc/sys /kernel/core_uses_pid 可以控制 Core 文件的文件名中是否添加 pid 作为扩展。若文件内容为1,表示添加pid作为扩展名,生成的 Core文件格式为core.pid;为 0 则表示生成的 Core 文件一命名为 core。


[administrator@JavaLangOutOfMemory ~ ]% echo "/corefile/core-%e-%p-%t" > core_pattern

  基于 /proc/sys/kernel/core_pattern可以控制 Core 文件保存位置和文件名格式。上述命令行操作可以将 Core 文件统一生成到 /corefile 目录下,产生的文件名为:core-命令名-pid-时间戳。其他类似的参数可参考如下:


%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加当前uid 
%g - insert current gid into filename 添加当前gid 
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号 
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间 
%h - insert hostname where the coredump happened into filename 添加主机名 
%e - insert coredumping executable name into filename 添加命令名 

    如何确定是 “Core Dump” 文件?

   在类 Linux 系统下,Core Dump 文件本身主要的格式也是 ELF ,因此,我们可以通过 readelf 命令进行判断,具体如下所示:


[administrator@JavaLangOutOfMemory ~ ]% readelf -h core

   基于上述命令,获取 “Type”关键字属性值,若为 “CORE (Core file)” ,则表示此文件为 Core Dump 文件。当然,我们也可以通过简单的 file 命令进行快速判断,具体如下所示:


[administrator@JavaLangOutOfMemory ~ ]% file core.10000

    上面我们讲了 Core 文件的生成,接下来,我们再简要解析下 Core 文件的使用与分析。通常情况下,所生成的 Core 文件是需要借助 gdb 工具来进行调试以及查看。具体可参考如下所示:


[administrator@JavaLangOutOfMemory ~ ]% gdb test core.coredump.2034.3291660340
GNU gdb Red Hat Linux (6.5-8.fc6rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
Error while mapping shared library sections:
libmylib.so: Success.
[administrator@JavaLangOutOfMemory ~ ]% gdb -core=core.10000

    然后,我们键入 “bt” 命令参数,此时,将会显示所更详尽的调用信息,基于此内容分析,我们便能够快速、准确定位出问题所在。通常,若有时候 Core Dump 只生成一个空文件,我们也可以借助 “file” 命令进行辅助查看。

    综上所述,Core Dump 文件对于分析类 Unix 操作系统环境下程序异常的作用是不言而喻的,具有十分重要的参考意义。基于其所具备的“问题复现”、“信息追踪”等特征,借助它,使得我们在疑难杂症面前,能够从容面对。

相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
相关文章
|
3月前
|
网络协议 Linux Docker
在Linux中,如何指定dns服务器,来解析某个域名?
在Linux中,如何指定dns服务器,来解析某个域名?
|
13天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
46 4
|
14天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
1月前
|
弹性计算 网络协议 Ubuntu
如何在阿里云国际版Linux云服务器中自定义配置DNS
如何在阿里云国际版Linux云服务器中自定义配置DNS
|
3月前
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
148 3
|
3月前
|
Linux C# C++
【Azure App Service For Container】创建ASP.NET Core Blazor项目并打包为Linux镜像发布到Azure应用服务
【Azure App Service For Container】创建ASP.NET Core Blazor项目并打包为Linux镜像发布到Azure应用服务
|
3月前
|
网络协议 Linux
在Linux中,如何改IP、主机名、DNS?
在Linux中,如何改IP、主机名、DNS?
|
3月前
|
域名解析 网络协议 Linux
在Linux中,我们都知道,dns采用了tcp协议,又采用了udp协议,什么时候采用tcp协议?什么 时候采用udp协议?为什么要这么设计?
在Linux中,我们都知道,dns采用了tcp协议,又采用了udp协议,什么时候采用tcp协议?什么 时候采用udp协议?为什么要这么设计?
|
3月前
|
缓存 网络协议 Linux
在Linux中,当用户在浏览器当中输入⼀个网站,计算机对dns解释经过那些流程?
在Linux中,当用户在浏览器当中输入⼀个网站,计算机对dns解释经过那些流程?
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2