目录
虚拟地址的内部结构

这张图中可以看到内存地址中按从低地址到高地址排列的内存块,分别是代码区,字符常量区,数据区包括未初始化的和已初始化的,堆。而栈的地址是从高地址到低地址。
可以通过代码来验证一下(Linux环境下)
int g_unval;
int g_val=100;
int main()
{
const char* s="hello world";
printf("code addr:%p\n",main);//代码区
printf("string rdonly addr:%p\n",s);//(字符串)常量区
printf("uninit addr:%p\n",&g_unval);//未初始化数据区
printf("init addr:%p\n",&g_val);//初始化数据区
char* heap =(char*)malloc(10);
printf("heap addr:%p\n",heap);//堆
printf("stack addr_string:%p\n",&s);//栈--栈上的临时空间
printf("stack addr_heap:%p\n",&heap);
int a=10,b=20;
printf("stack addr_a:%p\n",&a);//验证栈区地址是由大到小
printf("stack addr_b:%p\n",&b);
return 0;
}
[wjy@VM-24-9-centos 407test]$ ./mycode
code addr:0x40057d //代码区
string rdonly addr:0x400700 //字符常量区
uninit addr:0x601044 //未初始化数据区
init addr:0x60103c //初始化
heap addr:0x199a010 //堆
stack addr_string:0x7ffd05938bc8 //栈
stack addr_heap:0x7ffd05938bc0
stack addr_a:0x7ffd05938bbc
stack addr_b:0x7ffd05938bb8
那么C/C++的程序地址空间,是内存吗?
验证一下,写一个mycode.c的C语言程序。定义一个全局变量,这样父子进程用到这个值都会是这个值。当fork()创建子进程,结果为0就是子进程,如果不为0,fork()值为子进程的pid,那么就是父进程。当两个进程一样的时候,二者共用一份代码,一份数据。当子进程有改变的时候,就会发生写时拷贝。
[wjy@VM-24-9-centos 407test]$ cat mycode.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int g_val=100;
int main()
{
//数据是各自有一份(写时拷贝)
if(fork()==0)
{
//child
int cnt=5;
while(cnt)
{
printf("I am child,times:%d,g_val=%d,&g_val:%p\n",cnt,g_val,&g_val);
cnt--;
sleep(1);
if(cnt==3)//当cnt值为3改变g_val的数据
{
printf("############### child changed data ################\n");
g_val=200;
printf("############### child changed done ################\n");
}
}
exit(0);
}
else{
//parent
while(1)
{
本文详细探讨了Linux操作系统中程序的虚拟地址空间,包括mm_struct结构体、数据代码与虚拟地址的关系,以及虚拟地址如何通过页表和MMU转化为物理地址。通过实例解释了写时拷贝原理,阐述了地址空间对于内存管理和进程隔离的重要性。
最低0.47元/天 解锁文章

477

被折叠的 条评论
为什么被折叠?



