关于用户程序内存的管理的实验(再思考fork)

21 篇文章 0 订阅

 

如题,一般用户程序的内存分配图,此次使用c编程来检验,基于window os,使用编译器 GNU。

 

 

 

代码如下,(摘自一位linux 高手的测试代码)

 

#include <stdio.h>
#include <malloc.h>

// 未赋值的全局变量放在bss段
int global_var;

// 已赋值的全局变量放在data段
int global_initialized_var = 5;

void function() {  
   int stack_var; // 函数中的变量放在stack中

   // 放在stack中的变量
   // 显示其所在内存地值
   printf("the function's stack_var is at address 0x%08x\n", &stack_var);
}


int main() {
   int stack_var; // 函数中的变量放在stack中
   
   // 已赋值的静态变量放在data段
   static int static_initialized_var = 5;
   
   // 未赋值的静态变量放在bss段
   static int static_var;
   
   int *heap_var_ptr;

   // 由malloc在heap中分配所需内存,
   // heap_var_ptr这个指针指向这块
   // 分配的内存
   heap_var_ptr = (int *) malloc(4);

   // 放在data段的变量
   // 显示其所在内存地值
   printf("====IN DATA SEGMENT====\n");
   printf("global_initialized_var is at address 0x%08x\n", &global_initialized_var);
   printf("static_initialized_var is at address 0x%08x\n\n", &static_initialized_var);

   // 放在bss段的变量
   // 显示其所在内存地值
   printf("====IN BSS SEGMENT====\n");
   printf("static_var is at address 0x%08x\n", &static_var);
   printf("global_var is at address 0x%08x\n\n", &global_var);

   // 放在heap中的变量
   // 显示其所在内存地值
   printf("====IN HEAP====\n");
   printf("heap_var is at address 0x%08x\n\n", heap_var_ptr);

   // 放在stack中的变量
   // 显示其所在内存地值
   printf("====IN STACK====\n");
   printf("the main's stack_var is at address 0x%08x\n", &stack_var);
   printf("the main's heap_var_ptr is at address 0x%08x\n", &heap_var_ptr);
   printf("the function is at address 0x%08x\n", function);
   function(); 
   free(heap_var_ptr);
}


 

 


运行结果为:

====IN DATA SEGMENT====
global_initialized_var is at address 0x00404000
static_initialized_var is at address 0x00404004

====IN BSS SEGMENT====
static_var is at address 0x00407024
global_var is at address 0x00407020

====IN HEAP====
heap_var is at address 0x00581948

====IN STACK====
the main's stack_var is at address 0x0022feec
the main's heap_var_ptr is at address 0x0022fee8
the function is at address 0x004016b0
the function's stack_var is at address 0x0022febc

 

 

将之用 图表示出来:

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以上仅仅是一个进程的实验,于是自己改动程序,在linux下 使用fork()观察。

如下为变动程序

( cat /proc/versionLinux version 3.8.0-29-generic (buildd@akateko) (gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #42~precise1-Ubuntu SMP Wed Aug 14 15:31:16 UTC 2013)


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <malloc.h>



int main() {

   pid_t p;
   p=fork();
	   
	if(p==0)
	{
		printf("this is son\n");
		 int stack_var; // 函数中的变量放在stack中

   

   // 已赋值的静态变量放在data段

   static int static_initialized_var = 5;

   

   // 未赋值的静态变量放在bss段

   static int static_var;

   

   int *heap_var_ptr;



   // 由malloc在heap中分配所需内存,

   // heap_var_ptr这个指针指向这块

   // 分配的内存

   heap_var_ptr = (int *) malloc(4);



   // 放在data段的变量

   // 显示其所在内存地值

   printf("====IN DATA SEGMENT====\n");

   printf("static_initialized_var is at address 0x%08x\n\n", (unsigned int)&static_initialized_var);



   // 放在bss段的变量

   // 显示其所在内存地值

   printf("====IN BSS SEGMENT====\n");

   printf("static_var is at address 0x%08x\n", (unsigned int)&static_var);





   // 放在heap中的变量

   // 显示其所在内存地值

   printf("====IN HEAP====\n");

   printf("heap_var is at address 0x%08x\n\n", (unsigned int)heap_var_ptr);



   // 放在stack中的变量

   // 显示其所在内存地值

   printf("====IN STACK====\n");

   printf("the main's stack_var is at address 0x%08x\n", (unsigned int)&stack_var);

   free(heap_var_ptr);
	}
	else
	{
		printf("this is father\n");
		int stack_var; // 函数中的变量放在stack中

   

   // 已赋值的静态变量放在data段

   static int static_initialized_var = 5;

   

   // 未赋值的静态变量放在bss段

   static int static_var;

   

   int *heap_var_ptr;



   // 由malloc在heap中分配所需内存,

   // heap_var_ptr这个指针指向这块

   // 分配的内存

   heap_var_ptr = (int *) malloc(4);



   // 放在data段的变量

   // 显示其所在内存地值

   printf("====IN DATA SEGMENT====\n");

   printf("static_initialized_var is at address 0x%08x\n\n", (unsigned int)&static_initialized_var);



   // 放在bss段的变量

   // 显示其所在内存地值

   printf("====IN BSS SEGMENT====\n");

   printf("static_var is at address 0x%08x\n", (unsigned int)&static_var);





   // 放在heap中的变量

   // 显示其所在内存地值

   printf("====IN HEAP====\n");

   printf("heap_var is at address 0x%08x\n\n", (unsigned int)heap_var_ptr);



   // 放在stack中的变量

   // 显示其所在内存地值

   printf("====IN STACK====\n");

   printf("the main's stack_var is at address 0x%08x\n", (unsigned int)&stack_var);

   free(heap_var_ptr);
	}

  

}


运行结果为:

this is father
====IN DATA SEGMENT====
static_initialized_var is at address 0x0804a028

====IN BSS SEGMENT====
static_var is at address 0x0804a038
====IN HEAP====
heap_var is at address 0x08789008

====IN STACK====
the main's stack_var is at address 0xbfd780d0

this is son
====IN DATA SEGMENT====
static_initialized_var is at address 0x0804a024

====IN BSS SEGMENT====
static_var is at address 0x0804a034
====IN HEAP====
heap_var is at address 0x08789008

====IN STACK====
the main's stack_var is at address 0xbfd780d0 


在stack 和 heap段  father process 和 son process 有相同的地址。

为此 改了下程序,在if两个分支中添加下面几句话

heap_var_ptr = (int *) malloc(4);
   (*heap_var_ptr)=1;
   printf("son:: heap_var_ptr= %d\n",(*heap_var_ptr));

父进程中

   heap_var_ptr = (int *) malloc(4);
   printf("heap_var_ptr= %d\n",(*heap_var_ptr));

运行结果:

heap_var_ptr= 0
son:: heap_var_ptr= 1

即虽然同一地址,但是好像并没有共享数据。

又写了段简洁写的代码


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>

int add(int a,int b);
//全局变量
int global = 99;
char buf[] = "Input a string: ";

int main()
{
    pid_t   pid;
    int val,ret;
    int *str;
    val =49;
    str = (int*)malloc(sizeof(int));
    if((pid = fork()) == -1)
    {
        perror("fork() error");
        exit(-1);
    }
    if(pid == 0)   //子进程
    {
        static int p1;
	int* s_str;
	s_str = (int*)malloc(sizeof(int));
        printf("Child process start exec.\n");
	(*str)=1;
	printf("child::str in heap =ox%08x\n",(unsigned int)str);
	printf("child::p1 in stack =ox%08x\n",(unsigned int)&p1);
	printf("child::s_str in heap =ox%08x\n",(unsigned int)s_str);
        printf("son::global in data seg =ox%08x\n",(unsigned int)&global);
        global++;
        val++;
    }
    if(pid >0)   //父进程
    { 
         sleep(4);   //等待子进程执行
	 static int p2;
         int* s_str;
	 s_str = (int*)malloc(sizeof(int));
         printf("Parent process start exec.\n");
	 printf("parent::str in heap =ox%08x\n",(unsigned int)str);
	 printf("parent::p2 in stack =ox%08x\n",(unsigned int)&p2);
         printf("parent::s_str in heap =ox%08x\n",(unsigned int)s_str);
	 printf("parent::global in data seg =ox%08x\n",(unsigned int)&global);
    }
    printf("pid=%d,ppid=%d,global=%d,val=%d\n",getpid(),getppid(),global,val);
    //write(STDOUT_FILENO,buf,strlen(buf));
    //read(STDIN_FILENO,str,100);
    //write(STDOUT_FILENO,str,strlen(str));
    printf("main::str in heap =ox%08x\n",(unsigned int)str);
    printf("str=%d \n",(*str));
    ret = add(global,val);
    printf("global+val=%d\n",ret);
    exit(0);
}

int add(int a,int b)
{
    return (a+b);
}

运行结果如下

Child process start exec.
child::str in heap =ox091aa008
child::p1 in stack =ox0804a054
child::s_str in heap =ox091aa018
son::global in data seg =ox0804a034
pid=3473,ppid=3472,global=100,val=50
main::str in heap =ox091aa008
str=1
global+val=150
Parent process start exec.
parent::str in heap =ox091aa008
parent::p2 in stack =ox0804a058
parent::s_str in heap =ox091aa018
parent::global in data seg =ox0804a034
pid=3472,ppid=2260,global=99,val=49
main::str in heap =ox091aa008
str=0
global+val=148

由此 得出初步结论,kernel给进程分配时,使用的是虚拟地址,即虽然父进程和子进程有一样的地址实际物理地址不一样,就无法数据共享了。

网上找到一种解释:

VM分配与释放

“内存总是被进程占用”,这句话换过来可以这么理解:进程总是需要内存。当fork()或者exec()一个进程的时候,系统内核就会分配一定量的VM给进程,作为进程的内存空间,大小由BSS段,Data段的已定义的全局变量、静态变量、Text段中的字符直接量、程序本身的内存映像等,还有Stack段的局部变量决定。当然,还可以通过malloc()等函数动态分配内存,向上扩大heap。

动态分配与静态分配,二者最大的区别在于:1. 直到Run-Time的时候,执行动态分配,而在compile-time的时候,就已经决定好了分配多少Text+Data+BSS+Stack。2.通过malloc()动态分配的内存,需要程序员手工调用free()释放内存,否则容易导致内存泄露,而静态分配的内存则在进程执行结束后系统释放(Text, Data), 但Stack段中的数据很短暂,函数退出立即被销毁。



---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

由此又想到之前,一道面试题 关于函数返回变量地址,而此时变量已经释放的问题

http://www.lupaworld.com/article-229041-1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值