如题,一般用户程序的内存分配图,此次使用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