在UNIX上编程时,经常会遇到如下两个常见的运行时错误:
buserror(总线错误)
segmentationfault(段错误)
总线错误
总线错误几乎都是由于未对齐的读或写造成的。它之所以称为总线错误,是因为出现未对齐的内存访问请求时,被堵塞的组件就是地址总线。对齐的意思就是数据项只能存储在地址是数据项大小的整数倍的内存位置上。在现代的计算机架构中,尤其是RISC架构,都需要数据对齐,因为与任意的对齐有关的额外逻辑会使整个内存系统更大且更慢。通过迫使每个内存访问局限在一个cache行或一个单独的页面内,可以极大地简化如cache控制器或内存管理单元这样的硬件。
我们表达“数据项不能跨越页面或cache边界”规则的方法多少有些间接,因为我们用地址对齐这个术语来陈述这个问题,而不是直截了当说是禁止内存跨页访问,但它们说的是同一回事。例如,访问一个8字节的double数据时,地址只允许是8的整数倍。所以一个double数据可以存储于地址24、8008、32768,但不能存储于地址1006,页和cache的大小是经过精心设计的,这样只要遵守对齐规则就可以保证一个原子数据项不会跨越一个页或cache块的边界。
段错误
段错误通常是由于解除引用一个未初始化或非法值的指针引起的。以发生频率为序,最终可能导致段错误的常见编程错误是:
1、坏指针错误:在指针赋值之前就用它来引用内存;或者向库函数传递一个坏指针(如果调试器显示系统程序中出现了段错误,很可能并不是系统程序引起的段错误,问题可能就出现在自己的代码中);或者指针被释放后还继续访问它的内容。
2、改写错误:越过数组边界写入数据,在动态分配的内存空间以外写入数据,或改写一些堆管理数据结构(在动态分配的内存之前的区域写入数据就很容易发生这种情况)。
3、指针释放引起的错误:释放同一块内存两次,或释放一块未曾使用malloc分类的内存,或释放一个无效的指针。一个极为常见的与释放内存有关的错误就是在for(p=start;p;p=p->next)这样的循环中迭代一个链表,并在循环体内使用free(p)这样的语句。这样,在下一次循环迭代时,程序就会对已经释放的指针进行解除引用操作,从而导致不可预料的结果。