当前位置: 技术问答>linux和unix
Linux程序内存管理问题请教
来源: 互联网 发布时间:2016-04-22
本文导语: 现在脑子里一塌糊涂。 (1)先讲根源: 我在测试两个段错误的程序: code1: int main(void) { int a[4]; printf("a[4]=%dn",a[4]); printf("a[10000]=%dn",a[10000]); a[4]=5; printf("a[4]=%dn",a[4]); a[10000]=5; ...
现在脑子里一塌糊涂。
(1)先讲根源:
我在测试两个段错误的程序:
code1:
code2:
code1的执行结果是:
a[4]=-1078954782
Segmentation fault(core dump)
code2的执行结果是:
a[4]=-1078954782
a[1000]=0
a[4]=5
Segmentation fault(core dump)
再讲我的迷惑
我根据上面的现象将内存划分为一下使用情况:
1。可读写的区域 -----a[4]
2。只读不可写的区域--- a[1000]
3。不可读不可些的区域-- a[10000]
根据我的底子很薄的汇编知识,我妄加推断:
1。a[4]虽然数组地址边界越界,但仍在堆栈中,属于可读写区域
2。a[1000]在只读数据段中(本程序的也不知道别的程序的?)
3。a[10000]在代码段中(本程序的也不知道别的程序的?)
后来google了一下,发现代码段是只读的属性,所以a[1000]也可能指向代码段。
请高手帮我解释一下
(1)内存中什么区域是不可读写的?有没有可写不可读的区域?
(2)Linux对程序的空间是怎么管理的?是给内核分配一个固定的内存空间,给其他应用程序分配指定大小的空间还是其他方式?
(1)先讲根源:
我在测试两个段错误的程序:
code1:
int main(void)
{
int a[4];
printf("a[4]=%dn",a[4]);
printf("a[10000]=%dn",a[10000]);
a[4]=5;
printf("a[4]=%dn",a[4]);
a[10000]=5;
printf("a[10000]=%dn",a[10000]);
return 0;
}
code2:
int main(void)
{
int a[4];
printf("a[4]=%dn",a[4]);
printf("a[1000]=%dn",a[1000]);
a[4]=5;
printf("a[4]=%dn",a[4]);
a[10000]=5;
printf("a[1000]=%dn",a[1000]);
return 0;
}
code1的执行结果是:
a[4]=-1078954782
Segmentation fault(core dump)
code2的执行结果是:
a[4]=-1078954782
a[1000]=0
a[4]=5
Segmentation fault(core dump)
再讲我的迷惑
我根据上面的现象将内存划分为一下使用情况:
1。可读写的区域 -----a[4]
2。只读不可写的区域--- a[1000]
3。不可读不可些的区域-- a[10000]
根据我的底子很薄的汇编知识,我妄加推断:
1。a[4]虽然数组地址边界越界,但仍在堆栈中,属于可读写区域
2。a[1000]在只读数据段中(本程序的也不知道别的程序的?)
3。a[10000]在代码段中(本程序的也不知道别的程序的?)
后来google了一下,发现代码段是只读的属性,所以a[1000]也可能指向代码段。
请高手帮我解释一下
(1)内存中什么区域是不可读写的?有没有可写不可读的区域?
(2)Linux对程序的空间是怎么管理的?是给内核分配一个固定的内存空间,给其他应用程序分配指定大小的空间还是其他方式?
|
1 对用户程序来说,内核空间应该是不可读写的
可写的区域一定可读
2 看看 understanding linux kernel 中进程地址空间一章吧
可写的区域一定可读
2 看看 understanding linux kernel 中进程地址空间一章吧
|
每个进程中,都会有4G的进程空间,3g在用户空间,1G在内核空间,在程序中定义的变量,编译后就是进程的逻辑空间内给分配了一个地址,注意,这时候仅仅是个虚拟的地址而已,并没有实际的物理的对应空间.当程序运行时,并不一定就给就给这个地址影射真实的物理空间,当程序内要使用这个变量是,系统就会为它分配真实的物理空间,可能会多分配一些,它是按固定块分配的.这样,你使用时,按固定地址读写,没有问题,有时候多读写一点虽然已经溢出,但也没有问题.但超过实际的物理空间后要求后,系统就会住址你的物理要求了.
根据进程空间布局,代码段,数据区是只读型的,当你的过分的要求是他们时,就只能读不能写了.
有点乱,讲不清了.
|
回楼上的,
1,研究了这些问题后,才有可能实现定义数组越界的地方。比如某个大量引用的数组越界了,为了不更改大量代码,就必须找到具体的越界地址而更改程序的错误。
2,另外也可以帮助自己在写代码的时候时刻保持警惕!
|
对上面的问题作出如下看法:
一:完全是非法访问导致的结果,结果具有不可预知性
二:由一可以知道,非法访问包括读和写,楼主的代码一里面的第二个printf: printf("a[10000]=%dn",a[10000]);
将数组的数值改小为6000或者4000等,会出现同样的结果:段错误!只有更小的时候才会出现“随机”的结果,因此,根据程序一里面的数组a[10000])的数值10000来做的任何判断都是错误的。
三:根据一和二可以知道是非法访问,那么我们将数组改为int a[40000],系统会为你分配相应的栈,只要在范围以内,都是不会报错误的。
四:根据以上的结果,可以得出楼主的关于
“ 1。a[4]虽然数组地址边界越界,但仍在堆栈中,属于可读写区域
2。a[1000]在只读数据段中(本程序的也不知道别的程序的?)
3。a[10000]在代码段中(本程序的也不知道别的程序的?)
”
等的看法都是没有依据的,只是建立在非法访问的基础上的。但是!问题是,为什么会出现怎样的错误呢?...看上面的解释。。。
一:完全是非法访问导致的结果,结果具有不可预知性
二:由一可以知道,非法访问包括读和写,楼主的代码一里面的第二个printf: printf("a[10000]=%dn",a[10000]);
将数组的数值改小为6000或者4000等,会出现同样的结果:段错误!只有更小的时候才会出现“随机”的结果,因此,根据程序一里面的数组a[10000])的数值10000来做的任何判断都是错误的。
三:根据一和二可以知道是非法访问,那么我们将数组改为int a[40000],系统会为你分配相应的栈,只要在范围以内,都是不会报错误的。
四:根据以上的结果,可以得出楼主的关于
“ 1。a[4]虽然数组地址边界越界,但仍在堆栈中,属于可读写区域
2。a[1000]在只读数据段中(本程序的也不知道别的程序的?)
3。a[10000]在代码段中(本程序的也不知道别的程序的?)
”
等的看法都是没有依据的,只是建立在非法访问的基础上的。但是!问题是,为什么会出现怎样的错误呢?...看上面的解释。。。
|
1.
数组访问越界的结果是不可预料的,LZ的试验,只能说是某台机器某个系统在某个特定的时间运行的结果。
2.
printf和Segmentation fault的先后顺序不一定可靠。就是说,有可能先执行了某个printf然后出错,但是这个printf该打出来的东西可能在缓冲区里来不及打印,给人一种错觉就是这个printf没执行。
3.
不可写的地方不见得就是代码段。比如,函数的返回地址也在栈上,如果数组越界改写了返回地址,也会挂掉。
http://blog.csdn.net/k2eats/archive/2008/07/04/2610433.aspx
数组访问越界的结果是不可预料的,LZ的试验,只能说是某台机器某个系统在某个特定的时间运行的结果。
2.
printf和Segmentation fault的先后顺序不一定可靠。就是说,有可能先执行了某个printf然后出错,但是这个printf该打出来的东西可能在缓冲区里来不及打印,给人一种错觉就是这个printf没执行。
3.
不可写的地方不见得就是代码段。比如,函数的返回地址也在栈上,如果数组越界改写了返回地址,也会挂掉。
http://blog.csdn.net/k2eats/archive/2008/07/04/2610433.aspx
|
code1的
读a[10000]出错。原因1. 该地址没有分配内存;2. 即使分配了内存也没有范围权限。
code2的
写a[10000]出错。原因同上。
可读、写的情况是,该地址已分配了内存(无论是谁分配的)并有读写权限。
读a[10000]出错。原因1. 该地址没有分配内存;2. 即使分配了内存也没有范围权限。
code2的
写a[10000]出错。原因同上。
可读、写的情况是,该地址已分配了内存(无论是谁分配的)并有读写权限。