前段买了本《C专家编程》确实不错,特别是对内存思考这一章节,(O(∩_∩)O~目前我也只看到这一章节),其中讲到了总线错误和段错误:
bus error(core dumped) 总线错误(信息已经转储)
segmetation fault(core dumped)段错误( 信息已经转储 )
这种错误相信只要你在unix用c,c++这两种错误是常见又是很头疼的错误,目前我也遇到段错误的程序,至今未找到错误原因。来看看作者怎么解说的:
产生原因: 当硬件告诉操作系统一个有问题的内存引用时,操作系统通过发送信号给有问题的进程进行交流。(信号是一种事件通知或一个软件中断)。普通进程一般对“总线错误”或“段错误”信号将进行信息转储并且终止,俗称“程序coredump”。
(当然可以设置一个信号处理程序修改程序的缺省反应)。
总线错误:
引起原因: 几乎总是由于对未对齐的读或写引起的。它之所以称为总线错误是因为对未对齐的内存访问时,被阻塞的组件就是地址总线。
对齐(alignment)数据项只能存储在地址是数据项大小的整数倍的内存位置上,这样可以加速内存访问。如:访问一个8字节的double的数据时,地址只能是8的整数倍,所以存储一个double的地址只能是24,8008,但不能存储于地址1006因为它不能被8整除,只要保证这个原则,就可以保证一个原子项数据不会跨页或cache块的边界。
引起总线错误的小程序:
union
{
char a[10];
int i;
}u;
int *p =(int*)&(u.a[1]);
*p =17;/*p中未对齐的地址将会引起总线错误*/
因为数组和int的联合确保了a是按照int的4字节来对齐的,所以“a+1”肯定不是int来对齐的。(后面专门讨论下内存对齐问题)
段错误:
引起直接原因:
(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进行解除引用。
用dbx可以看出堆栈空间是否用完:
dbx a.out
(dbx) catch SIGSEGV
(dbx) run
...
signal SEGV(segmentation violation ) in <some_routine> at oxeff57708
(dbx)where
如果可以看到调用链说明堆栈空间还没有用完。如果看到以下情景:
fetch at oxeffe7a60 failed --- I/O error
(dbx)
那么堆栈空间已经用完,上面16禁止数就是可以提取或影射的堆栈地址。
C-SHELL中可以通过limit stacksize 10 来调整堆栈的空间为10K,进程的总线地址空间仍然收到交换区大小的限制,可以用swap -s命令查看交换区的大小。
bus error(core dumped) 总线错误(信息已经转储)
segmetation fault(core dumped)段错误( 信息已经转储 )
这种错误相信只要你在unix用c,c++这两种错误是常见又是很头疼的错误,目前我也遇到段错误的程序,至今未找到错误原因。来看看作者怎么解说的:
产生原因: 当硬件告诉操作系统一个有问题的内存引用时,操作系统通过发送信号给有问题的进程进行交流。(信号是一种事件通知或一个软件中断)。普通进程一般对“总线错误”或“段错误”信号将进行信息转储并且终止,俗称“程序coredump”。
(当然可以设置一个信号处理程序修改程序的缺省反应)。
总线错误:
引起原因: 几乎总是由于对未对齐的读或写引起的。它之所以称为总线错误是因为对未对齐的内存访问时,被阻塞的组件就是地址总线。
对齐(alignment)数据项只能存储在地址是数据项大小的整数倍的内存位置上,这样可以加速内存访问。如:访问一个8字节的double的数据时,地址只能是8的整数倍,所以存储一个double的地址只能是24,8008,但不能存储于地址1006因为它不能被8整除,只要保证这个原则,就可以保证一个原子项数据不会跨页或cache块的边界。
引起总线错误的小程序:
union
{
char a[10];
int i;
}u;
int *p =(int*)&(u.a[1]);
*p =17;/*p中未对齐的地址将会引起总线错误*/
因为数组和int的联合确保了a是按照int的4字节来对齐的,所以“a+1”肯定不是int来对齐的。(后面专门讨论下内存对齐问题)
段错误:
引起直接原因:
(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进行解除引用。
用dbx可以看出堆栈空间是否用完:
dbx a.out
(dbx) catch SIGSEGV
(dbx) run
...
signal SEGV(segmentation violation ) in <some_routine> at oxeff57708
(dbx)where
如果可以看到调用链说明堆栈空间还没有用完。如果看到以下情景:
fetch at oxeffe7a60 failed --- I/O error
(dbx)
那么堆栈空间已经用完,上面16禁止数就是可以提取或影射的堆栈地址。
C-SHELL中可以通过limit stacksize 10 来调整堆栈的空间为10K,进程的总线地址空间仍然收到交换区大小的限制,可以用swap -s命令查看交换区的大小。