谁能解释一下出现内存分段故障的条件?

发表于:2007-05-26来源:作者:点击数: 标签:
谁能解释一下出现内存分段故障的条件?谢谢! yuxq 回复于:2003-08-08 09:39:41 当申请一块内存以后,如果你指针越界,当他在没有超出你所申请的内存的页的大小时,即使指针越界,也可以使用,但是如果指针超出了你所申请的内存的那页,到了另外一内存页,

谁能解释一下出现内存分段故障的条件?谢谢!

 yuxq 回复于:2003-08-08 09:39:41
当申请一块内存以后,如果你指针越界,当他在没有超出你所申请的内存的页的大小时,即使指针越界,也可以使用,但是如果指针超出了你所申请的内存的那页,到了另外一内存页,就会出现segmentation fault (分段故障)

 kj501 回复于:2003-08-08 12:56:37
自问自答,呵呵!

 蓝色键盘 回复于:2003-08-08 13:07:24
[quote:a95f84788c="yuxq"]当申请一块内存以后,如果你指针越界,当他在没有超出你所申请的内存的页的大小时,即使指针越界,也可以使用,但是如果指针超出了你所申请的内存的那页,到了另外一内存页,就会出现segmentation fault (分段故障)[/quote:a95f84788c]     

呵呵,你说的有一定的道理,系统按照一定的大小管理内存页面,这个页面的大小也不是固定的哦,有些是4096字节,有些是8194,对于段违例而言,除了于页面的大小有关外,还于内存保护算法有关,这个算法一般能够处理到4自己是否发生违例,遗憾的是,有些系统可能压根没有这个保护措施,例如sco unix,很可能是完全针对页面大小保护。

 yuxq 回复于:2003-08-08 14:01:33
谢谢斑竹更深入的解释!

 alexai 回复于:2003-08-08 14:42:49
请试试下面的程序
int main(){
  char *p0,*p1,*p2;
  p1= malloc(40000); // 在;p0heap分配足够大的一块
  p0= malloc(10);
  p2= malloc(40000);
 
  *(p0+2*4096)=1;
}

 alexai 回复于:2003-08-08 14:56:04
解释一下,
分配三块内存区,其中两块足够大,其中一块p0小些,希望malloc将小的那块夹在两块大的中间,这个我没有试过,但是作为例子足够了,然后,用*(p0+2*4096)越界访问,这时候p0+2*4096已经越过了malloc分配的区,而且肯定越过了它所在的页面,,但是,segment fault没有发生。呵呵。但是你把p2=malloc(40000)去掉,segement fault就发生了。

原因呢,因为系统不是因为内存访问超越malloc分配区发生段访问异常,也不是因为越过了页面发生异常,而是因为访问了不存在的页,或者有写保护的页,其他例子嘛:请看:

char * str="I love BSD";
int main(){
*(str+1)='1';
}
一样的会段异常,这是因为str指向的内存区在代码段,这个段的页面是有写保护的。

欢迎指正

 alexai 回复于:2003-08-08 14:58:06
对不起,后面那个例子搞错了,那个会出现bus error,有兴趣的看看manual吧,要上班了

 alexai 回复于:2003-08-08 17:28:13
更准确地意思:
seg fault 一般是访问不存在的页面时, 不存在的叶面就是没有被os分配页面的地址空间, 如:进程的第一页,0x0000-0x4095, heap区以上&&stack段以下的区域. 如果进程试图访问这些地址,哪怕是只读, 都会产生seg fault,这个异常是由于MMU在影射地址时找不到页面所致.

还有就是bus error, 一般这是因为进程试图write只读的段segment导致的, 一般只读的段包括: text 段,也就是你的代码区, 全局只读data段,也就是.rodata段, 这个段里放的是字符串常量的内容. 

(我还没有搞清楚的是, .data 和.rodata 可以在同一个页面中, cpu如何区同一个页面中一部分是只读的,另一部分是可写的 :()

在有些机器上, 试图读写不对齐的的字段会导致bus error, 但是我试了gclearcase/" target="_blank" >cc+BSD+intel,不会产生.

你要是有兴趣的话,可以自己写简单的代码来试试. 

如果你幸运, 一个指针跳到了只读段或者不存在页面的地址上,你很快就能知道.
但是你如果不幸运, 一个指针跳了可读写的地方, 嗬嗬, 那就是噩梦了. 
所以小心你的指针哦.

 odin_free 回复于:2003-08-16 21:43:30
segement fault简直太经常出现了
有时在使用指针(数组)的时候,同意alexai的看法

 xa_butterfly 回复于:2003-08-17 16:33:32
碰到segment fault我头都大了.
我前一段时间就碰到个怪问题:
在aix5.1下编译安装mysql-4.0.14,用了一段时间,有一天突然有些客户端程序一运行就出segment fault的错误,重装也不管用.后来不知怎么就又好了.哎

 yuxq 回复于:2003-08-18 08:43:32
内存分页的原因

 xa_butterfly 回复于:2003-08-18 08:47:28
关键问题是怎么避免和解决这类问题啊

 youngS 回复于:2003-08-18 13:05:02
[quote:ed1708df04="alexai"]解释一下,
分配三块内存区,其中两块足够大,其中一块p0小些,希望malloc将小的那块夹在两块大的中间,这个我没有试过,但是作为例子足够了,然后,用*(p0+2*4096)越界访问,这时候p0+2*4096已经越过了malloc分配?.........[/quote:ed1708df04]
我相信你的这个结论也是随机的,并不是确定的。
malloc分配的内存之间也许是连续的也许不是连续的,因此你用两块大内存来夹一个小内存是不合理的。用malloc分配的同一块内存是连续的,但是不同malloc之间的也许是不连续的,所以你不能这样来做试验。

 yuxq 回复于:2003-08-18 13:43:43
应该指定申请内存的起始指针测出的结果才是准确的!

 youngS 回复于:2003-08-18 14:31:39
[quote:802992a751="xa_butterfly"]关键问题是怎么避免和解决这类问题啊[/quote:802992a751]
你申请了多大的内存就使用多大的内存,这样就不会错。

 xa_butterfly 回复于:2003-08-18 15:19:54
对于我碰到的问题,能给我一个合理的解释吗

 alexai 回复于:2003-08-20 17:42:10
[quote:ae1dff74e1="youngS"]
我相信你的这个结论也是随机的,并不是确定的。
malloc分配的内存之间也许是连续的也许不是连续的,因此你用两块大内存来夹一个小内存是不合理的。用malloc分配的同一块内存是连续的,但是不同malloc之间的也许是?.........[/quote:ae1dff74e1]     

我同意你的看法,我这么做的原因是作为一个例子来说明问题,是不是连续可以看看分配的地址如何。我在BSD上试过了,证明是连续的。
二则要说明的是,seg fault的原因不是因为越过malloc的界或者页的界,而是因为试图访问没有映射vm页的地址空间。
谢谢你的指正。

 蓝色键盘 回复于:2003-08-23 19:22:55
[quote:592440b21d="alexai"]请试试下面的程序
int main(){
  char *p0,*p1,*p2;
  p1= malloc(40000); // 在;p0heap分配足够大的一块
  p0= malloc(10);
  p2= malloc(40000);
 
  *(p0+2*4096)=1;
}[/quote:592440b21d]     

这样的结构是:不论哪种malloc,大多数情况OS会按照存储器管理的页面大小再堆中sbrk一块区域,这个sbrk相当于批发。实际上比你要用的要大一些。然后这些页面便挂接再进程的内存页面表项中。处理的时候,首先是按照页面存储和修改数据,但是保护的措施分为多种情况,

完了再描述,有事情要走了。。。。

 ohwww 回复于:2003-10-10 14:00:24
老大,走了这么长时间还不回来解释???等ing

原文转自:http://www.ltesting.net

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)