当这些电路在执行指令的过程中检测到某些特定条件时,会立即中断当前控制流,并强制 CPU 去执行一段预设好的、属于操作系统的代码。这个过程是硬件自动完成的。...内核的陷阱处理程序 (Trap Handler): 接管控制权:当 CPU 触发上述硬件异常时,它会根据异常类型自动查找 IDT,并立即跳转到对应的内核陷阱处理程序代码执行。...寄存器状态:程序计数器(PC)、栈指针(SP)等,这直接指向了崩溃时正在执行的代码。 程序计数器值:明确指出是哪条指令导致了崩溃。 内存管理信息:页表、文件描述符表等资源信息。...Core Dump 文件提供了重现崩溃现场的一切信息。借助调试器(如 GDB),你可以: 精确定位崩溃位置:直接看到崩溃时程序执行到了哪一行代码、哪个函数。...这样,当写入发生时,系统调用(如 write())不会导致进程终止,而是会返回 -1 并设置错误码 errno 为 EPIPE。程序可以通过检查返回值来进行更优雅的错误处理。
,崩溃 s[] = 'H'; } 访问了进程没有权限访问的地址空间(比如内核空间) // 针对进程的内核空间写入数据,崩溃 *p = ; } 访问了不存在的内存,比如 以上错误都是访问内存时的错误...(假设为 11,即 SIGSEGV,一般非法访问内存报的都是这个错误) 操作系统根据情况执行相应的信号处理程序(函数),一般执行完信号处理程序逻辑后会让进程退出 注意上面的第五步,如果进程没有注册自己的信号处理函数...如代码所示:注册信号处理函数后,当收到 SIGSEGV 信号后,先执行相关的逻辑再退出 另外当进程接收信号之后也可以不定义自己的信号处理函数,而是选择忽略信号,如下 #include ...这种场景显然不能用 kill -9,不然一下把进程干掉了资源就来不及清除了 为什么线程崩溃不会导致 JVM 进程崩溃 现在我们再来看看开头这个问题,相信你多少会心中有数,想想看在 Java 中有哪些是常见的由于非法访问内存而产生的...,只是虚拟机不选择退出,而是自己内部作了额外的处理,其实是恢复了线程的执行,并抛出 StackoverflowError 和 NPE,这就是为什么 JVM 不会崩溃且我们能捕获这两个错误/异常的原因 如果针对
但是当信号产生时,我们可能在做着其他事情,会把信号暂时不做处理。 暂不处理就要求我们记得这个信号,并确定什么时候处理。 对此,如果把上面的“我们”换成“进程”,就是进程中的信号了!...ID,并且当接收到SIGINT信号*(2号信号)时,会调用handler函数打印出信号编号。...通常情况下,当你运行这个程序并按下Ctrl+C时,程序会打印出"get sig:2"并继续运行,因为它已经处理了SIGINT信号。如果你想要终止程序,使用kill命令。...再来试试 int *p = nullptr; *p = 100; 也崩溃了,那么为什么程序会崩溃呢??? 因为程序非法访问,导致OS给进程发送信号,进程就崩溃了。...CR2 - 控制寄存器2: 用于存储导致页错误的线性地址,当发生页错误异常时,CPU会自动将出错的线性地址加载到CR2中。
信号产生是异步的:信号的产生和目标进程的运行是两条线,信号可以在程序的任意时刻产生,并且会打断当前正在执行的代码,转而执行信号处理函数。...如果把所有信号都捕捉了,会出现什么现象: 无论哪一个信号都无法终止程序,为了避免这种情况,系统中9号信号不允洗自定义捕捉 真正发送信号的是操作系统,只有操作系统可以发送信号。...,那么程序为什么会崩溃?...程序非法访问导致操作系统给进行发送信号,由于收到信号,程序会退出。野指针对应发送的信号时SIGSEGV,除0对应的信号为SIGFPE。...除0错误:在计算机的CPU中,有一个eflag寄存器,这个寄存器中有一个溢出标记位,当10和0进行除法运算时,在计算机中其实相当于做了多次加法运算,此时溢出标记位标记为1,表示溢出,此时CPU内部报错。
如果handler为SIG_IGN,表示忽略该信号,即当收到指定信号时不进行任何处理。 如果handler为SIG_DFL,表示使用系统默认的处理方式,通常是终止进程或执行默认操作。...一般来说,abort()函数被用于发现程序中的严重错误,并且需要立即终止程序执行。...我们想要产生core文件的话:ulimit -c选项设置core file的大小 core文件 为什么要有这个文件:我们想通过core来知道进程为什么退出,以及执行到哪行代码退出的 是什么:将进程在内存中的核心数据...当程序出现内存越界、段错误(Segmentation Fault)或其他异常情况导致崩溃时,操作系统会中止该进程,并将当前内存状态、寄存器状态、堆栈指针、内存管理信息以及各个函数使用堆栈信息等保存到Core...同时,由于Core文件是在程序崩溃时自动生成的,因此它也可以作为一种自动记录程序崩溃信息的机制,方便程序员进行事后分析和排查。
崩溃转储、内存转储、核心转储、系统转储……这些全都会产生同样的产物:一个包含了当应用崩溃时,在那个特定时刻应用的内存状态的文件。...目录,运行 make,并使用 -c1 开关执行该示例二进制: ....当使用 systemd-coredump 时,转储文件被压缩保存在 /var/lib/systemd/coredump 下。你不需要直接接触这些文件,你可以使用 coredumpctl。...: (gdb) info locals nDivider = 0 nRes = 5 结合源码,可以看出,你遇到的是零除错误: nRes = 5 / 0 结论 了解如何处理转储文件将帮助你找到并修复应用程序中难以重现的随机错误...而如果不是你的应用程序,将核心转储转发给开发人员将帮助她或他找到并修复问题。
,即当特定信号发生时,程序应该执行的函数。...除零错误 (Division by zero) 当程序试图将一个数除以零时,CPU会产生一个硬件异常,因为这是非法的数学运算。...触发过程: 当程序执行除法运算时,如果除数为零,CPU的算术逻辑单元(ALU)会检测到这个错误。 CPU无法执行除以零的运算,因此会产生一个硬件异常,通常是SIGFPE(浮点异常)信号。...命令类似:gdb · 这样可以在程序已经结束后,回溯检查崩溃时的变量值、函数调用栈等信息,帮助定位导致程序崩溃的根本原因(例如,是哪一行代码出了问题...当程序需要执行一个系统调用(比如读取文件、分配内存等)时,它会触发一个 软中断(如 int 0x80),并通过这个中断请求操作系统的帮助。
/sig 首先在后台执行死循环程序,然后用kill 命令 给它发SIGSEGV信号 $ kill -SIGSEGV 213784 $ // 多按⼀次回⻋ [1]+ Segmentation fault...3.5.1 除 0 问题 关于进程中的计算问题,一般都是交由 cpu 来完成的,在计算的过程中,难免会出现错误的计算,比如说除0,那么 cpu 又是如何知道的呢?...当操作系统决定重新调度这个进程时,会进行上下文切换,即将当前进程的上下文保存到其PCB(进程控制块)中,并加载异常进程的上下文到CPU寄存器中。...当 MMU 无法找到一个虚拟地址对应的物理地址时(例如,解引用空指针或野指针),会触发一个页错误(page fault)。...这个文件包含了进程在内存中的状态信息,对于程序员来说是非常有用的调试工具。 core 动作则更常用于在进程崩溃时生成调试信息,帮助程序员找出崩溃的原因。
我们想必都有过因为大意而让数据进行\0操作或者对野指针解引用的操作,往往这些情况出现的时候我们的程序就会崩溃,那么为什么\0,野指针会导致程序崩溃呢?...na 而如果是野指针操作,同样也是程序没有执行完就终止了,我们看到报的错就是Segmentation fault,也就是段错误,那这个信号又是谁呢?...2号信号和9号信号都是由用户主动向进程所发送的,于是进程被终止了,所以我们不关心它是怎么被终止的,但是8号信号和11号信号是由用户所写的代码出现了异常所引起的,我们是可以通过进程崩溃所返回的信息知道进程是因为什么原因崩溃了...,但是我们同样也更想知道到底是代码的哪一行导致程序的崩溃。...我们就来看看: 要使用这个core文件,使用方法如上图所示:core-file + core文件名称,就可以直接定位到导致程序崩溃的那一行代码了,行号也标了出来。
如果连续发实时信号,那么进程会将队列中的信号一个个全部处理 3、core dump 我们在《进程控制》一文中解释了wait函数的status参数,其中第7位就是core dump标志,这里简单解释一下 当程序在运行过程中发生崩溃...(如段错误、除零错误等),Core dump 会记录下程序崩溃瞬间的内存状态,包括寄存器的值、调用栈信息、全局变量和局部变量的值等,开发人员可以使用调试工具(如 GDB)加载 Core dump 文件,...通过分析这些信息,准确地找到程序崩溃的位置和原因 我们可以通过ulimit -c 10240将core文件的大小限制修改为10240字节,出现错误的时候core文件可能瞬间会被打满的,所以我们云服务器上一般默认...也是一个位图,与block一致,对应的下标和信号编号也是一一对应,当对应比特位为1时,表示该编号信号处于未决状态,为0则信号递达 实际上block和pending都属于保存信号,只不过因为有两个位图,我们分开来说罢了...为0来到pending,pending为0来到handler执行动作,其中,9号和19号新号还是特例,它们是不能被阻塞和保存的,这两个信号一旦发出就是直接handler,其实也不用handler了,它们对应的不可能为忽略和信号捕捉后的自定义函数
无论是我们熟悉的Ctrl+C终止进程,还是程序运行中出现的段错误、定时器超时,本质上都是信号被触发产生的过程。很多开发者只知道 “信号能终止进程”,却不清楚信号到底是怎么来的 —— 是用户操作触发的?.../sig_alarm_catch 终端输出如下,1 秒后进程打印统计结果并退出: 进程PID:12355,设置1秒后触发闹钟... 1秒时间到!...这类信号的本质是:硬件错误通过 OS 转换为软件层面的信号,让进程有机会处理错误(如打印日志、保存数据),若不处理则执行默认动作(通常是终止进程并生成 Core Dump)。...6.1 核心案例 1:除零操作 —— 触发 SIGFPE 信号(8 号) 当进程执行 “除以零” 的算术运算时,CPU 的运算单元会检测到该错误,通知 OS,OS 将其映射为SIGFPE...6.2 核心案例 2:非法内存访问 —— 触发 SIGSEGV 信号(11 号) 当进程访问非法内存地址(如空指针、数组越界)时,MMU(内存管理单元)会检测到该错误,通知 OS,OS
;所以可以说:**号是发送给进程的,而信号是一种事件通知的异步通知机制 在计算机操作系统中,信号是发送给进程的,而信号是一种事件通知的异步通知机制 简单来说就是,进程在没有收到信号时,在执行自己的代码...但是这里是修改了进程对于1-32的处理方式的(9和19无法修改),并且进程在收到abort发送的6号信号之后,是执行了自定义处理发送handler的,那为什么进程还是退出了?...硬件异常 我们知道,当程序中存在/0、野指针(越界访问)时,进程就会直接退出;那进程是如何退出的呢? 答案就是信号,当程序出现错误时,OS统就会给当前进程发送信号从而杀掉进程。...操作系统是如何知道程序出错了呢? 当程序出错时,操作系统会通过信号杀掉进程,那操作系统是如何知道程序出错了呢?...野指针同理,当进行野指针访问时,CPU在执行时发出错就会触发硬件中断,然后执行OS相关方法。
它的出现往往让我们措手不及,同时大概率会导致程序行为异常。尽管从最早的版本这个异常就贯穿在我们的编码世界里,但它背后却隐藏着深刻的历史和设计哲学。...这导致了无数错误、漏洞和系统崩溃,可能在过去四十年里造成了十亿美元的损失和痛苦。”但从今天的软件系统发展来看,空引用对业界的影响远不止这一数字。...如下是OpenJDK9中虚拟机的代码,3个方法主要做了三件事情:install_signal_handlers(): 虚拟机启动时注册信号,这里完成了SIGSEGV的捕获注册set_signal_handler...如下方注释所说,当虚拟机收到操作系统回调时,如果发现是SIGSEGV信号且对应的内存offset为0,会主动返回并抛出NullPointerException,系统也并不会崩溃。...NPETest如上是一个简单的例子,当加载的JNI代码中存在手工捕获了SIGSEGV之后,面对NullPointerException虚拟机只能无奈以崩溃告终,并生成堆转储文件。
无论是我们日常按下Ctrl+C终止进程,还是程序出现段错误、除零异常,背后都是信号在发挥作用。很多 Linux 初学者会觉得信号晦涩难懂,其实它的逻辑和我们生活中的场景高度相似。...这个过程和 Linux 进程处理信号的逻辑几乎一模一样,我们来拆解每一个环节: 信号识别:你看到快递员的电话,就知道是快递到了,不需要别人额外解释 —— 这对应 Linux 进程对信号的内置识别能力,内核程序员在设计进程时...2 SIGINT 终端按下 Ctrl+C 终止进程 3 SIGQUIT 终端按下 Ctrl+\ 终止进程并生成 core dump 9 SIGKILL kill -9 进程 PID 终止进程(不可捕捉...主要有两个原因: 进程可能在执行高优先级任务:比如进程正在执行内核态的代码(如系统调用),此时处理信号可能会破坏内核数据结构,导致系统崩溃,因此需要等进程从内核态返回到用户态时再处理; 信号处理的原子性...5.1 Ctrl+\:SIGQUIT 信号,终止进程并生成 core dump SIGQUIT信号的默认动作是终止进程并生成 core dump 文件,core dump 文件是进程的内存镜像文件,包含了进程终止时的内存数据
所以进程一旦出异常了,不一定会退出,但是一旦异常退出了,一定是执行了信号所对应的异常处理方法。 (2)理解本质 下面我们进一步理解为什么除0错误和野指针会让进程崩溃。...本质上是出现异常后,给对应的进程发信号了,而进程收到信号默认的处理动作就是终止自己,这就是进程崩溃的原因。那么为什么除0错误和野指针会给进程发信号呢?...除0错误 当进程执行代码的时候,我们知道,CPU中的eip或者pc指针会保存代码的下一条指令的地址;其中还有一种寄存器叫做状态寄存器,其中有一个比特位表示状态标志位,称为溢出标志位,当我们发生除0的时候...那么当溢出标志位溢出之后,操作系统需要知道CPU出现溢出了吗?计算出错了吗?需要!操作系统在调度进程时必须要知道已经出现异常了,因为操作系统是硬件的管理者!CPU也是硬件!...那么为什么要进行核心转储呢?其实当发生核心转储时,一定发生了运行时错误,当发生了运行时错误,我们肯定最想知道发生了什么错误,而且更想知道代码在哪一行出错了!
1.1.1 重入的定义 当一个函数被不同的控制流程调用,在第一次调用还未执行完毕时,再次进入该函数执行,这种现象称为函数重入。...flag)循环永远执行,检测不到flag的变化,信号仿佛 “失效” 了。 2.2 问题根源:编译器的寄存器优化 为什么开启-O2优化后会出现这种问题?...,信号仿佛 “失效”; 正确使用:用volatile修饰主程序和信号处理函数共享的全局 / 静态标志位,并结合sig_atomic_t类型,保证操作的原子性,定义为volatile sig_atomic_t...操作系统内核代码、驱动程序、系统调用 用户应用程序代码、标准库函数 触发方式 系统调用、中断、异常 进程启动后默认的执行状态 错误影响 执行错误会导致系统崩溃(如内核 panic) 执行错误仅会导致当前进程崩溃...、数据、栈、堆、环境变量等,进程在用户态时只能访问该区域; 内核空间(3-4GB):所有进程共享,存放 Linux 内核的代码、数据结构(如 PCB、信号集)、驱动程序等,只有进程进入内核态时才能访问该区域
当我们的程序在运行过程中崩溃了,我们一般会通过调试来进行逐步查找程序崩溃的原因。...return 0; } 使用gdb对当前可执行程序进行调试,然后直接使用core-file core文件命令加载core文件,即可判断出该程序在终止时收到了8号信号,并且定位到了产生该错误的具体代码。...由硬件异常产生信号 为什么C/C++程序会崩溃? 当我们程序当中出现类似于除0、野指针、越界之类的错误时,为什么程序会崩溃?...总结一下: C/C++程序会崩溃,是因为程序当中出现的各种错误最终一定会在硬件层面上有所表现,进而会被操作系统识别到,然后操作系统就会发送相应的信号将当前的进程终止。...执行操作系统的代码,将当前进程的代码和数据剥离下来,并换上另一个进程的代码和数据。 注意: 当你访问用户空间时你必须处于用户态,当你访问内核空间时你必须处于内核态。
它包含程序在失败时的状态快照、所有线程的堆栈信息,可用于调试,是用来分析 Crash 问题的最佳工具。...但某些时候,coredump 文件 不一定能顺利生成,这个时候就需要从 observer.log 中获取崩溃时的堆栈,分析崩溃位置的代码,以此来寻找原因。本文介绍的就是这个方法。...获取崩溃点具体的代码位置 如何确认具体执行到 ObMPStmtExecute::copy_or_convert_str 函数的哪一行?...崩溃信息中 sig=11,也就是 signal 11,表示程序访问了无效的内存地址,通常是由于空指针引用或者访问了已经释放的内存。...崩溃位置的这段代码的逻辑与 bug 描述吻合:在处理 execute 协议时,send long data 协议还没有把 param_data 信息处理完,因此 execute 协议在转换 param_data
可以用一个简单的curl请求来打印结果: curl http://localhost:8080/hello 也可以用对应的kill杀死了对应的进程: kill -9 {pid} 但有一个问题: 如果程序因为代码问题而意外退出...根据其对 原子性 的要求,我将处理逻辑区分为两种: 一种是无严格数据质量要求的,即程序直接崩溃也没有问题,比如一个普通查询; 另一种是有 原子性 要求的,即不希望运行到一半就退出,例如写文件、修改数据等...而优雅退出,则是希望能执行完当前的Sleep再退出。 一对一的解决方案 我们先简化问题:主函数对应的是一个需要优雅关闭的协程。...面向错误编程 - 关键业务的Goroutine 里代码要考虑所有可能发生错误的点,保证程序退出或panic/recover也不要出现 脏数据。...总结 main函数是go程序的入口,如果在这里写出一段优雅的代码,很容易给阅读自己源码的朋友留下良好的印象。