Chinaunix首页 | 论坛 | 博客
  • 博客访问: 656515
  • 博文数量: 516
  • 博客积分: 4119
  • 博客等级: 上校
  • 技术积分: 4288
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-30 17:29
文章分类

全部博文(516)

文章存档

2014年(4)

2013年(160)

2012年(352)

分类:

2012-11-01 11:20:37

原文地址:linux进程内存管理 作者:graylocus

 

1.数据的内部存储
 大端:起始地址存放数据的高位
 小端:起始地址存放数据的低位
 
 大端小端是由处理器的体系结构决定的,不是操作系统。
 
测试方法:

点击(此处)折叠或打开

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     int a=0x12345678;
  5.     char *p=NULL;
  6.    
  7.     p=&a;
  8.     if(*p = 0x12)
  9.        printf("big endian.\n");
  10.     else
  11.        printf("little endian.\n");

  12.     return 0;
  13. }

2.C程序的存储布局--代码段

代码段是用于存放CPU要执行的指令段。代码段只读,任何对代码段的修改,都会造成段错误。

一个程序在多数情况下是不需要修改自身代码的,只有一种情况例外,就是一些长时间运行的升级程序。

可以采用共享库的形式,来修改一个运行中的程序的代码段。

3.C程序的存储布局--数据段和缓冲段

初始化数据段(.data):也称为数据段。包含初始过的全局变量和静态变量。该段的大小在编译时确定

未初始化数据段(.bss,block start with symbol):这个段中的数据是程序没有明确初始化的静态变量+全局变量。又叫做块缓存段,块存储段

在elf格式的目标文件中,bss段并不占用实际的空间,而只是一个占位符,已告知指定位置上应当预留全局数据的空间。块缓存段存在的原因是为了提供磁盘上存储空间的利用率。

未初始化数据段不会存储在外存上,在程序运行时,由内核将段中的数据初始化成0或NULL。

4.C程序的存储布局--栈

所有的自动变量+函数调用时所需要保存的信息(返回地址,函数调用前各寄存器的值)都保存在栈中。

每个函数都有对应的栈帧。栈帧在一个函数调用时被创建,在函数调用结束时消亡。所有的函数都是基于进程的栈创建的,从全局的角度来看,一个进程只有一个栈(也只有一个堆),但每个函数执行时,都对应一块独立的栈帧。所以不应该在栈帧上传递一个返回值的地址,因为函数调用结束后,该栈帧有可能会被覆盖掉,相应的,对该地址的引用就会是无效的。

注意:不应该将一个指向局部变量的指针作为返回值返回。在linux环境下,这种方法是错误的。但Windows平台下,似乎是可行的。

函数调用结束后,栈帧上的内容还存在,函数返回的是一个局部变量的地址。如果该栈帧被其他函数覆盖,对该指针的引用也就失效了。

 

5.C程序的存储布局--堆

堆,用于存储用户申请的内存空间,系统通常在堆中进行动态内存分配。

对于小端处理器,栈地址由高-->低,堆地址由低-->高增长。大端处理器正好相反。


6.常量的存储

C语言中常量有两种:简单常量,如1234,‘c';复杂常量,如iloveyou等字符串常量。

在汇编语言中,对于常量参与运算的C语句,如a+1的汇编代码被汇编成如下:

点击(此处)折叠或打开

  1. mov r1, a
  2. add r1, 1

简单常量,它随着指令一起存储,也就是说简单变量存储在程序的代码段里。

对于复杂常量,长度不定,放在代码段里面是不明智的,因此编译器将其存储在一个特殊的数据段,将其存储的首地址转换成一个简单变量随着指令存储。这个段叫做.rodata段。


 7.动态内存管理

C语言中只能通过malloc和其他派生函数动态申请内存,malloc作为一个库函数,它的linux版本封装了

sbrk()系统调用,该系统调用负责向操作系统申请内存。malloc函数分配的内存在堆中,全局有效。

文件:malloc.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. void fenpei1(int **p)
  4. {
  5.     *p = (int *)malloc(sizeof(int));
  6. }

  7. void fenpei2(int *p)
  8. {
  9.     printf("the heap is %d\n",*p);
  10. }

  11. int main(void)
  12. {
  13.     int *p;
  14.     
  15.     fenpei1(&p);
  16.     *p=4;
  17.     fenpei2(p);
  18.     
  19.     free(p);
  20.     fenpei2(p);
  21.     return 0;
  22. }
  23. 运行:./malloc
  24.      the heap 4
  25.      the heap 0

做如下改动:

点击(此处)折叠或打开

  1. void fenpei1(int *p)
  2. {
  3.     p = (int *)malloc(sizeof(int));
  4. }

将fenpei1函数修改为如上形式。传递给fenpei1函数的是int *p的一份拷贝,p在函数返回后就消失了。

这时,p所指向的还是一块未知区域,再对p进行解引用赋值就出错了。


 

 

 

 

 

阅读(162) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~