news 2026/8/22 11:11:37

Linux进程虚拟地址空间:从实验到内核结构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux进程虚拟地址空间:从实验到内核结构

前言

每一个程序都以为自己独占一段内存空间,这个错觉是谁给的,同时,为什么创建子进程之后父子进程打印出相同的地址值但是值又是不相同的。这些问题就要通过今天的学习便可一一破解。

一、进程地址空间

1、进程地址空间图

2、虚拟地址空间的直接证明

int main()
{
int val=0;
pid_t id=fork();
if(id==0)
{
val=100;
printf("child[%d], val:%d &val:%p\n",getpid(),val,&val);
}
else if(id>0)
{
sleep(1);
printf("parent[%d], val:%d &val:%p\n",getpid(),val,&val);
}
return 0;
}

可以看到的是父子进程地址一样但是值却不一样的情况,那么也就证明了这个地址是虚拟地址而并不是真实的物理地址,并且拥有各自的地址,通过某种方式去映射到了同一个虚拟地址空间。

二、进程虚拟地址空间全景图

1、代码验证

通过上边的图片可以看到虚拟地址空间的全景图,此时我们通过程序将地址打印出来,看看地址的分布情况。

#include <stdio.h>
#include <stdlib.h>
int g_unval; // 未初始化全局变量 -> BSS
int g_val = 100; // 初始化全局变量 -> 数据段
int main(int argc, char *argv[], char *env[])
{
const char *str = "helloworld"; // 字符串常量 -> 只读数据区(文本段附近)
static int test = 10; // 初始化静态变量 -> 数据段
char *heap1 = malloc(10); // 堆
char *heap2 = malloc(10);
int stack_var; // 栈(注意取地址方式)

printf("code addr: %p\n", main);
printf("init global addr: %p\n", &g_val);
printf("uninit global addr: %p\n", &g_unval);
printf("static addr: %p\n", &test);
printf("string literal addr: %p\n", str);
printf("heap1 addr: %p\n", heap1);
printf("heap2 addr: %p\n", heap2);
printf("stack var addr: %p\n", &stack_var);
printf("argv[0]: %p\n", argv[0]);
printf("env[0]: %p\n", env[0]);
return 0;
}

ji'lu

可以得到这个地址与上边的实景图大致相符。

2、深入问题:为什么栈和堆要相向而生

通过图片可以看到,堆和栈中间有一个共享区,此时的话栈向下生长,堆向上生长,此时就可以最大化的共享中间区域,并且可以动态的调整。也就是说最大的利用空间。

三、虚拟地址和物理地址:页表和映射

1、简述虚拟地址的由来,程序编译链接时,会为代码段,数据段等分配逻辑地址。当程序被加载到内存后,这个逻辑地址就是虚拟地址。

当CPU处理一个虚拟地址时

(1)将虚拟地址拆分成虚拟页号(高位)以及页内偏移(低位)。

(2)拿着虚拟页号当作数组下标,去页表里找到对应的记录。

(3)检查权限,如果有效位为0则触发缺页中断,则操作系统会去磁盘里获取数据

(4)得到的记录与页内偏移量拼接后就是所得到的物理地址。

2、缺页中断:按需分配的核心

当进程调用malloc时,只是将堆顶上的指针向高处移动了而已,并没有给malloc扩容分配新的物理页,当真正写入访问的时候才会去分配新的物理页并建立映射。

指令 : pamp -x PID <-这个指令可以拆开每一段,看堆栈的大小。

验证惰性分配实验:

int main()
{
char *p=malloc(100*1024*1024);
printf("p=%p \n",p);
getchar();
for(int i=0;i<100*1024*1024;i+=4096)
{
p[i]=0;
}
printf("accessed\n");
getchar();
return 0;
}
观察现象(注:kbytes是虚拟内存大小 RSS是物理内存)

当我们执行代码是第一个getchar之后的运行结果可以得到第一张图,可以发现虚拟内存大小是100mb,当执行第二个getchar之后得到的运行结果可以得到第二张图,可以发现虚拟内存大小和物理内存大小相等,也就是说当写入访问的时候才会去分配物理内存。

四、内核如何描述和管理地址空间

1、task_struct(PCB)与mm_struct

前文得知,进程中都会存在属于自己的PCB,这个PCB内部有一个指针指向mm_struct也就是内存描述符。

struct task_struct {
// ...
struct mm_struct *mm; // 用户空间内存描述符
struct mm_struct *active_mm; // 内核线程借用
// ...
};

mm_struct定义了用户地址空间布局,是管理虚拟内存的。但准确的来说不是虚拟内存本身

struct mm_struct {
// ...
unsigned long start_code, end_code; // 代码段起止
unsigned long start_data, end_data; // 数据段起止
unsigned long start_brk, brk; // 堆起止(brk是当前堆顶)
unsigned long start_stack; // 栈起始
unsigned long arg_start, arg_end; // 命令行参数区
unsigned long env_start, env_end; // 环境变量区
// ...
};

2、vm_area_struct每个区域都是独立个体

一个进程的地址空间可能包含多个虚拟内存区域(VMA),例如:

  • 代码段一个VMA
  • 数据段一个VMA
  • 堆一个VMA
  • 栈一个VMA
  • 每个动态库一个VMA

内核用vm_area_struct来描述每个VMA

五、为什么要存在虚拟内存

1、安全

如果没有虚拟内存的话可能进程A通过指针去访问修改进程B的数据,如果存在虚拟内存的话每一个进程都只能访问自己的虚拟内存中页表所映射的物理空间。

2、效率

程序运行不需要把所有的数据放入内存之中,用到哪个就放哪个,甚至内存紧张时可以通过swap交换到磁盘中以此缓解内存紧张。

3、地址确定性

程序只需要知道虚拟内存地址就可以通过映射去访问真实的物理内存。

4、解耦与灵活性

malloc申请虚拟内存空间,物理内存只要不访问就可以是0。

只有真正访问写入时才会申请物理空间。

程序视角下,内存是连续的,但是物理空间可能散布各处。

后续

更新进程控制

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/22 11:11:30

深入解析Pub/Sub系统局限性:从消息语义到运维实战的避坑指南

Pub/Sub&#xff08;发布/订阅&#xff09;系统是构建现代分布式应用、微服务解耦和实时数据流处理的核心基础设施。但很多团队在引入或深度使用这类系统时&#xff0c;会遇到一个典型困境&#xff1a;初期一切顺利&#xff0c;随着业务量增长和场景复杂化&#xff0c;各种“意…

作者头像 李华
网站建设 2026/8/22 11:10:52

开源双臂机器人Hei-rebot-lift实战:从零搭建具身智能平台

如果你对机器人、AI和自动化感兴趣&#xff0c;但总觉得“具身智能”这类前沿概念离自己太远&#xff0c;或者认为搭建一台能实际工作的机器人需要昂贵的预算和专业的实验室&#xff0c;那么这篇文章就是为你准备的。最近&#xff0c;一个名为Hei-rebot-lift的开源项目在开发者…

作者头像 李华
网站建设 2026/8/22 11:10:24

Python 连接 DeepSeek API,OpenAI 两种对话方式基础实现

上一节-Python 连接 DeepSeek API&#xff0c;OpenAI的基础操作 文章目录三、进阶功能 1&#xff1a;实现多轮上下文对话1、技术原理&#xff1a;传递对话历史2、完整代码示例3、代码关键点解析四、进阶功能 2&#xff1a;实现流式输出1、技术原理2、完整代码示例3、代码关键点…

作者头像 李华
网站建设 2026/8/22 11:09:29

对抗性评估基准:如何构建鲁棒AI规划智能体的压力测试

1. 项目背景与核心问题&#xff1a;为什么我们需要一个“对抗性”的规划基准&#xff1f; 在人工智能领域&#xff0c;尤其是围绕大型语言模型构建的智能体&#xff0c;我们正见证着一场从“对话”到“行动”的范式转移。一个能说会道的模型固然令人印象深刻&#xff0c;但一个…

作者头像 李华
网站建设 2026/8/22 11:06:26

AI Agent安全实践指南:从德州学生举报事件看智能体安全防护

这次我们来看一个关于AI安全与伦理的警示案例。标题“Texas student blew the whistle on a rogue AI hacking attempt”直指核心&#xff1a;一名学生如何发现并举报了一次由AI驱动的、意图不当的“黑客”尝试。这并非一个具体的开源工具或模型&#xff0c;而是一个真实发生的…

作者头像 李华
网站建设 2026/8/22 11:06:26

绕过DeepSeek灰测门槛:三种合法接入方法与实战指南

如果你最近关注AI编程助手&#xff0c;可能会发现一个现象&#xff1a;很多开发者都在讨论DeepSeek的“灰测版本”&#xff0c;但似乎只有少数“内部人士”或“DSH”才能体验到。这种信息差让不少想尝鲜的开发者感到困惑&#xff1a;难道真的只能干等着官方公测吗&#xff1f;实…

作者头像 李华