首页 园地图库文章列表留言下载
现在位置:首页 -> 网络科技 -> 上网指南
Linux操作系统概述9
作者:佚名 来源:mmkey.com搜集 更新日期:2004-10-1 阅读次数
文字 〖 自动滚屏(右键暂停)

5.5.2 页错误 文摘园地
假设上面那个例子中页表入口的第11位为0,这代表了需要的页并没有装入内存中,这一事件就被称为页错误。如果它发生了,CPU会产生一个内部中断,会导致到OS的强行跳转。OS首先会决定将内存中的哪个已置位页写回到硬盘以腾出空间,然后它会将请求的页从硬盘中写入相应位置,此后OS会更新页表中的两个入口参数:(a)它会修改被覆盖的页的入口参数,将第11位置0,并重置3112位;(b)它会更新新载入的页的入口参数,指明该页已经装载入内存了,并且说明它的位置。
因为读写硬盘的速度远远慢于读写内存的速度,因此,如果页错误出现的太多,程序的运行速度就会非常迟缓。举个例子,假如你家里的PC机内存不够,那么你会发现装载大型软件的时候需要等待很长时间,并且硬盘指示灯会闪得很厉害,就是因为OS要将许多当前置位的页写回硬盘、并从硬盘中装载入新的页。 文摘园地
5.5.3
访问破坏 文摘园地
另一方面,如果发生一个访问破坏,那么OS会声明一个错误-—-UNIX系统中,把这个错误称为段错误-—-并会导致进程被杀死,也就是从进程表中移除。
举个例子,参看下面的代码: 文摘园地
int q[200]; 文摘园地
main()
{ int i;
for (i = 0; i < 2000; i++)~ {
q[i] = i;
}
} 文摘园地
注意到编程者很显然在循环结构中犯了个错误,他将叠代数200替换成了2000C编译器在编译过程中会忽略该错误,并且编译出的机器代码在执行过程中也不会检查到数组索引超界了。
如果该程序在非VM平台上运行,那么它可以畅快的没有任何明显错误的运行。它会简单的在q数组后写入1800个字,这能否造成破坏就取决于多余的字数据的目的了。
不过在VM平台上,这里就是UNIX系统下,实际上会报告一个错误,和一个段错误的信息。不过,在我们深入理解该错误之前,它出现的时间或许会另你吃惊。这个错误不像是在i=200时出现的,而像是在此之后很长一段时间才出现的。
为了说明它,我选择在gdb下运行此程序以便我能够查看q[199]的地址。在运行该程序之后,我发现段错误不是出现在i=200处,而是出现在i=728的时候。让我们看看这是为什么。
通过查询gdb我发现数组q是在地址0x080497bf处结束的,也就是说,q[199]这个最后的元素处于该地址空间中。对于Intel的机器,页大小为4096字节,所以一个虚拟地址被分成20位的页号和12位的偏移量,正如在5.5.1节中所述的那样。在我们目前这个例子中,q结束于虚拟页号为0x8049、十进制为32841,偏移量为0x7bf、十进制为1983的位置处。所以,在q[199]之后,还有4096-1984=2112个字节空间在同一个页中可供使用。这写空间如果用于存储int型变量,可以存储2112/4=528个,也就是说,可以储存从q[200]q[727]528个元素。当然,实际上它们并不是q数组的元素,不过正如前面讲的,编译器并不会对此提出异议。同样的,硬件也不会,由于我们拥有对页的写权限,因此我们可以把相应的数据写入这些空间中。不过当i自增到728时,会使程序使用一个新页,该页不会付予我们写权限(或者其他任何权限),这会被硬件发现,并且硬件会触发段错误。
不仅试图读写超过范围的数据项会导致段错误,同样,试图执行超过范围的指令也会导致段错误。举例说明,考虑下面的代码: 文摘园地
1 int f(int x)
2 {
3 return x*x;
4 }
5
6 int (*p)(int);
7
8 main()
9 {
10 p = f;
11 u = (*p)(5);
12 printf("%d\n",u);
13 }
如果我们忘了写如下一行: 文摘园地
u=(*p)(5); 文摘园地
那么变量p不会指向任何函数,也就是说,我们会企图执行超出我们程序范围的空间中的代码,这就会导致段错误。

上篇文章: Linux操作系统概述续10
下篇文章:七夕礼物
相关文章:
没相关文章

版权所有:文摘园地;本站资料均由站长收集,如果有侵权,请立即来信留言告诉我们,以免损害您的权益,谢谢!
Copyright © 2004 文摘园地 http://wwww.mmkey.com All Rights Reserved Power by:HeadWind
粤ICP备05098767号