赞
踩
程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码。
初始化过的数据(Data):在程序运行初已经对变量进行初始化的数据。
未初始化过的数据(BSS):在程序运行初未对变量进行初始化的数据。
栈 (Stack):存储局部、临时变量,函数调用时,存储函数的返回指针,用于控制函数的调用和返回。在程序块开始时自动分配内存,结束时自动释放内存,其操作方式类似于数据结构中的栈。
堆 (Heap):存储动态内存分配,需要程序员手工分配,手工释放.注意它与数据结构中的堆是两回事,分配方式类似于链表。
上图中蓝色区域表示映射到物理内存的虚拟地址,而白色区域表示未映射的部分。可以看出,Firefox使用了相当多的虚拟地址空间,因为它占用内存较多。
进程地址空间中最顶部的段是栈,大多数编程语言将之用于存储函数参数和局部变量。调用一个方法或函数会将一个新的栈帧(stack frame)压入到栈中,这个栈帧会在函数返回时被清理掉。由于栈中数据严格的遵守FIFO的顺序,这个简单的设计意味着不必使用复杂的数据结构来追踪栈中的内容,只需要一个简单的指针指向栈的顶端即可,因此压栈(pushing)和退栈(popping)过程非常迅速、准确。进程中的每一个线程都有属于自己的栈。
通过不断向栈中压入数据,超出其容量就会耗尽栈所对应的内存区域,这将触发一个页故障(page fault),而被Linux的expand_stack()处理,它会调用acct_stack_growth()来检查是否还有合适的地方用于栈的增长。如果栈的大小低于RLIMIT_STACK(通常为8MB),那么一般情况下栈会被加长,程序继续执行,感觉不到发生了什么事情。这是一种将栈扩展到所需大小的常规机制。然而,如果达到了最大栈空间的大小,就会栈溢出(stack overflow),程序收到一个段错误(segmentation fault)。
你可以通过阅读文件/proc/pid_of_process/maps来检验一个Linux进程中的内存区域。记住:一个段可能包含许多区域。比如,每个内存映射文件在mmap段中都有属于自己的区域,动态库拥有类似BSS和数据段的额外区域。有时人们提到“数据段”,指的是全部的数据段+BSS+堆。
你还可以通过nm和objdump命令来察看二进制镜像,打印其中的符号,它们的地址,段等信息。最后需要指出的是,前文描述的虚拟地址布局在linux中是一种“灵活布局”,而且作为默认方式已经有些年头了,它假设我们有值RLIMT_STACK。但是,当没有该值得限制时,Linux退回到“经典布局”,如下图所示:
C语言程序实例分析如下所示:
- #include<stdio.h>
- #include <malloc.h>
-
- void print(char *,int);
- int main()
- {
- char *s1 = "abcde"; //"abcde"作为字符串常量存储在常量区 s1、s2、s5拥有相同的地址
- char *s2 = "abcde";
- char s3[] = "abcd";
- long int *s4[100];
- char *s5 = "abcde";
- int a = 5;
- int b =6;//a,b在栈上,&a>&b地址反向增长
-
- printf("variables address in main function: s1=%p s2=%p s3=%p s4=%p s5=%p a=%p b=%p \n",
- s1,s2,s3,s4,s5,&a,&b);
- printf("variables address in processcall:n");
- print("ddddddddd",5);//参数入栈从右至左进行,p先进栈,str后进 &p>&str
- printf("main=%p print=%p \n",main,print);
- //打印代码段中主函数和子函数的地址,编译时先编译的地址低,后编译的地址高main<print
- }
-
- void print(char *str,int p)
- {
- char *s1 = "abcde"; //abcde在常量区,s1在栈上
- char *s2 = "abcde"; //abcde在常量区,s2在栈上 s2-s1=6可能等于0,编译器优化了相同的常量,只在内存保存一份
- //而&s1>&s2
- char s3[] = "abcdeee";//abcdeee在常量区,s3在栈上,数组保存的内容为abcdeee的一份拷贝
- long int *s4[100];
- char *s5 = "abcde";
- int a = 5;
- int b =6;
- int c;
- int d; //a,b,c,d均在栈上,&a>&b>&c>&d地址反向增长
- char *q=str;
- int m=p;
- char *r=(char *)malloc(1);
- char *w=(char *)malloc(1) ; // r<w 堆正向增长
-
- printf("s1=%p s2=%p s3=%p s4=%p s5=%p a=%p b=%p c=%p d=%p str=%p q=%p p=%p m=%p r=%p w=%p \n",
- s1,s2,s3,s4,s5,&a,&b,&c,&d,&str,q,&p,&m,r,w);
- /* 栈和堆是在程序运行时候动态分配的,局部变量均在栈上分配。
- 栈是反向增长的,地址递减;malloc等分配的内存空间在堆空间。堆是正向增长的,地址递增。
- r,w变量在栈上(则&r>&w),r,w所指内容在堆中(即r<w)。*/
- }
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。