根据前面所述,可执行文件的type=LOAD的segment才会被装载,但是并不会把所有的data和code都加载到内存,因为这样浪费空间也没有必要;装载的时候是按照page(默认为4KB,也就是0x1000)对齐的方式进行加载,加载之后,程序运行时所访问的地址仍然是虚拟地址,这个虚拟地址就是前文所述的“内存虚拟地址”,而 加载之后的数据毕竟是存在于“物理内存”中的,所以这个“内存虚拟地址”和“物理内存地址”之间需要有一个转换,而这个转换工作是“MMU”物理部件来完成的;MMU物理部件管理“内存虚拟地址”到“物理内存地址”的映射;
程序运行到某个代码段或者访问数据的时候,如果在内存中找不到数据,那么就会产生一种叫做page fault的异常,然后进入异常处理程序,而这个异常处理的过程所作的事情是: 把数据从物理磁盘或者swap空间 调入到内存,并做好“虚拟内存地址” 到“物理内存地址”的mapping. 处理完异常之后,程序会回到原来的断点继续运行;
如果程序在运行的过程中发生了内存访问错误,通常会触发core dump, 如果系统开启了core dump, 那么会导出当时的系统内存映像到一个core dump的文件里面,然后可以用gdb 工具对这个core dump 文件进行调式,从而尽可能获得当时的内存状况,分析发生crash的原因,core dump 中使用的地址依然是”内存虚拟地址“, 所以 在程序运行的过程中,我们完全可以不考虑”内存物理地址“,因为”内存虚拟地址“ 到”内存物理地址“的mapping 对程序员来说是透明的,即便是进行debug,也无需关心”内存物理地址“。
下面简要说明core dump 如何开启以及配置:
- "ulimit -c SIZE" 用于指定core file的大小(默认单位为KB),如果触发core dump时候的大小 超过指定的SIZE, 那么也不会进行core dump. 这个值默认为0, 表示不进行core dump, 最大可以设置为 unlimited . 建议设置为 memory的大小;ulimit 命令设置的大小在重起后就失效了,所以最好写入 /etc/profile 之类的文件;
- 设置core dump发生时候对应的文件路径以及名称,比如: echo "/root/core.%P" >/proc/sys/kernel/core_pattern 表示生成的路径在/root/ 下, 文件名为:core.%P , 其中扩展参数可以用来限定dump文件的名称,具体如下:
%p - insert pid into filename
%u - insert current uid into filename
%g - insert current gid into filename
%s - insert signal that caused the coredump into the filename
%t - insert UNIX time that the coredump occurred into filename
%h - insert hostname where the coredump happened into filename
%e - insert coredumping executable name into filename
默认的路径为: /var/logs, 而因为默认的/var/logs 并不是系统自带的路径,所以必须手动创建该目录,否则 core dump 触发的时候也不会生成相应的文件.
- 配置完成,要检验是否可以成功生成coredump 文件,可以通过发送信号的方式来测试:
[root@www kernel]# bash #产生一个新的session
[root@www kernel]# ulimit -c unlimited
[root@www kernel]# echo "/root/core_%p_%s_%e.%h.%t" >./core_pattern
[root@www kernel]# kill -s SIGSEGV $$ #发送信号,让其触发core dump.
Segmentation fault (core dumped)
[root@www kernel]# ls -l /root | grep core #生成的core dump 文件
-r--------+ 1 root root 1417216 Mar 8 17:06 core_3427_11_bash.www.my.com.1583658365
[root@www kernel]#
上面例子,表示成功生成了core dump 文件,core dump的配置成功完成;