2014年(5)
分类: C/C++
2014-03-24 11:05:50
在UNIX上编程时,经常会遇到如下两个常见的运行时错误:
bus error (总线错误)
segmentation fault (段错误)
总线错误
总线错误几乎都是由于未对齐的读或写造成的。它之所以称为总线错误,是因为出现未对齐的内存访问请求时,被堵塞的组件就是地址总线。对齐的意思就是数据项只能存储在地址是数据项大小的整数倍的内存位置上。在现代的计算机架构中,尤其是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) 这样的语句。这样,在下一次循环迭代时,程序就会对已经释放的指针进行解除引用操作,从而导致不可预料的结果。
总线错误引起原因: 几乎总是由于对未对齐的读或写引起的。它之所以称为总线错误是因为对未对齐的内存访问时,被阻塞的组件就是地址总线。
段错误引起原因:
引起直接原因:
(1)解除引用一个包含非法值的指针。
(2)解除引用一个空指针(常常是从系统返回,却未经过检查)。
(3)未得到正确权限进行访问。如:向只读文本段存储值就回引起段错误。
(4)用完了堆栈或堆空间。
出现频率来分:
1 坏指针值错误:指针赋值前用它来引用内存;或向库函数传递坏指针(系统程序出现坏指针问题很可能还是出自自己的代码中);指针释放后还访问他的内容,
指针释放后,一定要把它置为NULL。
2 改写错误:越过数组边界写入数据,在动态分配内存两端写数据,或改写一堆管理数据结构(在动态内存两端写数据就会引起这种错误)。
p= malloc(256); p[-1]=0; p[256]=0;
3 指针释放引起的错误:释放一个内存块两次,或释放一个未曾用malloc分配的内存,或释放正在使用中的内存,或释放一个无效的指针。
如:
for(p = start; p; p= p->next)
{
free(p);
}
存在程序对下一次循环中对释放的指针p进行解除引用。