【Linux】程序地址空间(是什么?为什么?) 📅 发布时间:2026/7/11 14:56:21 👁️ 浏览次数: 一、程序地址空间回顾我们在学习C语言时都接触过这样的空间布局图我们对其不是特别理解我们可以先对其各区域进行分布验证#include stdio.h #include unistd.h #include stdlib.h int g_unval; int g_val 100; int main(int argc, char *argv[], char *env[]) { const char *str helloworld; printf(code addr: %p\n, main); printf(init global addr: %p\n, g_val); printf(uninit global addr: %p\n, g_unval); static int test 10; char *heap_mem (char*)malloc(10); char *heap_mem1 (char*)malloc(10); char *heap_mem2 (char*)malloc(10); char *heap_mem3 (char*)malloc(10) printf(heap addr: %p\n, heap_mem); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem1); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem2); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem3); //heap_mem(0), heap_mem(1) printf(test static addr: %p\n, test); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem1); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem2); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem3); //heap_mem(0), heap_mem(1) printf(read only string addr: %p\n, str); for(int i 0 ;i argc; i) { printf(argv[%d]: %p\n, i, argv[i]); } for(int i 0; env[i]; i) { printf(env[%d]: %p\n, i, env[i]); } return 0 }code addr: 0x400416 init global addr: 0x403020 uninit global addr: 0x40302c heap addr: 0x171e96b0 heap addr: 0x171e96d0 heap addr: 0x171e96f0 heap addr: 0x171e9710 test static addr: 0x403024 stack addr: 0x7ffc76d2b388 stack addr: 0x7ffc76d2b380 stack addr: 0x7ffc76d2b378 stack addr: 0x7ffc76d2b370 read only string addr: 0x40185c argv[0]: 0x7ffc76d2d580 env[0]: 0x7ffc76d2d587 env[1]: 0x7ffc76d2d597 env[2]: 0x7ffc76d2d5ae env[3]: 0x7ffc76d2d5ca env[4]: 0x7ffc76d2d5d8 env[5]: 0x7ffc76d2d5ef env[6]: 0x7ffc76d2d5fb env[7]: 0x7ffc76d2d610 env[8]: 0x7ffc76d2d61f env[9]: 0x7ffc76d2d62e env[10]: 0x7ffc76d2d63f env[11]: 0x7ffc76d2dd58 env[12]: 0x7ffc76d2dd87 env[13]: 0x7ffc76d2dd9e env[14]: 0x7ffc76d2dda9 env[15]: 0x7ffc76d2ddcc env[16]: 0x7ffc76d2ddd5 env[17]: 0x7ffc76d2ddfd env[18]: 0x7ffc76d2de05 env[19]: 0x7ffc76d2de1a env[20]: 0x7ffc76d2de36 env[21]: 0x7ffc76d2de58 env[22]: 0x7ffc76d2de71 env[23]: 0x7ffc76d2dee6 env[24]: 0x7ffc76d2df19 env[25]: 0x7ffc76d2df33 env[26]: 0x7ffc76d2df46 env[27]: 0x7ffc76d2df57 env[28]: 0x7ffc76d2dfe8二、虚拟地址我们之前在进程概念的学习中创建过子进程那我们刚好可以观察一下当子进程修改某一共享变量时父子进程读取到的该变量的值是否会发生改变该变量的地址又呈现出什么样的内容#include stdio.h #include unistd.h #include stdlib.h int g_val 0; int main() { pid_t id fork(); if(id 0) { perror(fork); return 0; } else if(id 0) { //child printf(child[%d]: %d : %p\n, getpid(), g_val, g_val); } else{ //parent printf(parent[%d]: %d : %p\n, getpid(), g_val, g_val); } sleep(1); return 0 }我们发现输出出来的变量值和地址是⼀模⼀样的很好理解呀因为⼦进程按照⽗进程为模版⽗ ⼦并没有对变量进⾏进⾏任何修改。可是将代码稍加改动:int main() { //子进程修改value值的情况 pid_t idfork(); if(id0) { perror(fork()); } else if(id0) { g_val100; printf(child[%d]:%d:%p\n,getpid(),g_val,g_val); } else { printf(parent[%d]:%d:%p\n,getpid(),g_val,g_val); } return 0; }我们发现⽗⼦进程输出地址是⼀致的但是变量内容不⼀样变量内容不一样说明父子进程输出的变量一定不是同一个变量但地址是一样的说明此地址一定不是物理地址在Linux地址下这种地址是虚拟地址。我们在⽤C/C语⾔所看到的地址全部都是虚拟地址物理地址⽤⼾⼀概看不到由OS统⼀ 管理OS必须负责将 虚拟地址转化成 物理地址。三、进程地址空间所以我们意识到开头最先看的图片不是物理内存分布图而是进程空间分布图。3.1分页、虚拟地址空间这个图足矣说明问题同一个变量地址相同其实都是虚拟地址相同内容不同其实是因为被映射到不同的物理地址。虚拟地址空间是个结构体变量页表承担着虚拟地址和物理地址映射的作用3.2写时拷贝这里还有个写时拷贝的现象子进程继承了父进程的g_val变量如果子进程不修改这个变量值那么它们共享这个变量g_val在同一个物理位置如果子进程要改变变量的值这时会在物理内存上拷贝一份g_val变量供子进程使用这就是写时拷贝现象通常⽗⼦代码共享⽗⼦再不写⼊时数据也是共享的当任意⼀⽅试图写⼊便以写时拷⻉的方式各⾃⼀份副本。如图因为有写时拷贝技术的存在,所以父子进程得以彻底分离离!完成了进程独立性的技术保证! 写时拷贝,是一种延时申请技术,可以提高整机内存的使用率。四、虚拟内存管理linux下进程的地址空间的所有信息的结构体是mm_struct内存描述符每个进程只有一个mm_struct在每个进程的task_struct结构中有一个指向mm_struct的结构体指针。倘若我们遇到堆区的动态开辟空间呢可能一个程序在堆区上会malloc很多次地址不同区域不同会被分成很多份这时候一个start和end指针能管理过来吗其实也无需担心linux内核会使用vm_area_struct结构来表示一个独立的虚拟内存区域VMA再采用单链表或者红黑树的方式vm_area_struct结构来连接各个VMA方便进程快速访问。五、为什么要有虚拟地址空间呢1.要保护物理内存如果每个进程都可以访问任意的内存空间这也就意味着任意进程都可去读写系统相关内存区域这是高危的行为2.因为有地址空间的存在和页表的映射的存在我们的物理内存中可以对未来的数据进行任意位置的加载物理内存的分配和进程的管理就没有关系了进程管理模块和内存管理模块就完成了解耦合。注所以我们之前在new和malloc空间时其实是在虚拟地址空间上申请的物理内存可以甚至一个字节都不给你而当你真正需要对物理地址空间进行访问时才执行相关的管理算法来帮你申请内存构建页表映射关系做到延时分配而这个操作是由操作系统自动完成的用户0感知缺页中断时其实就是在动态内存分配3.因为有页表的映射存在程序在物理内存中理论上可以在任意位置加载它可以将地址空间上的虚拟地址和物理地址进行映射在进程视角所有的内存分布都可以是有序的这里再补充一个进程挂起的小知识进程挂起其实就是找到页表把页表右侧的物理地址清除然后把代码数据换出到磁盘的指定区域。
豆包 LintCode 2798 · Aop 简化日志 你想要解决的是 LintCode 2798 这个关于使用 AOP(面向切面编程)简化日志记录的问题,核心需求应该是通过 AOP 的方式,在不侵入业务代码的前提下,为方法添加统一的日志记录功能。 问题分析与实现思路 AOP 的核心思想是横切关注点,日志记录就是典型的横切关注点。我们可以… 2026/3/18 16:38:40
Kali Linux 渗透测试基础操作与漏洞利用笔记 一、环境准备与系统配置1.1 环境虚拟机平台:VMware操作系统:Kali Linux(网络安全人员专用系统)1.2 换源(更换为国内镜像源,提升下载速度)sudo apt update编辑源列表文件:sudo nano /… 2026/5/17 4:25:55
[Keil 5] MDK-ARM快速搭建工程教程 提示:本文章旨在快速搭建工程项目(基于GD32芯片),其他方面略过 文章目录 前言 一、准备GD32F470固件库和支持包 二、新建工程文件夹 三、打开Keil5软件 前言 本文档不包含该开发工具的安装指南。 默认您已提前完成该开发环境… 2026/5/17 9:18:35
麦克纳姆轮车的导航规划 REF:移动机器人自主导航系统研究1. 机器人模型麦克纳姆轮:一种比较独特的车轮结构,通常由一组斜向的棍子组成,每个轮子上都有若干个斜向安装的滚轮,每个滚轮轴与轮毂呈一定角度,通常是45,分为左… 2026/7/11 14:55:26
终极VIA键盘配置器桌面版:3步打造专属机械键盘布局 终极VIA键盘配置器桌面版:3步打造专属机械键盘布局 【免费下载链接】releases 项目地址: https://gitcode.com/gh_mirrors/re/releases VIA键盘配置器桌面版是一款革命性的开源工具,专为机械键盘爱好者设计,通过Electron技术封装&… 2026/7/11 14:55:26
bilibili-downloader完全指南:轻松下载B站大会员4K高清视频 bilibili-downloader完全指南:轻松下载B站大会员4K高清视频 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 你是否曾因为网… 2026/7/11 14:53:26
Windows11安装阿里魔搭ModelScope并下载模型 Windows11安装阿里魔搭ModelScope并下载模型 一、创建并激活 Python 虚拟环境(推荐) py -m venv modelscope-env # or python -m venv modelscope-env #next modelscope-env\Scripts\activate二、安装 ModelScope 库 基础安装(仅支持模型… 2026/7/11 14:53:26
JS-YAML实战:破解JavaScript配置管理的性能瓶颈与数据解析难题 JS-YAML实战:破解JavaScript配置管理的性能瓶颈与数据解析难题 【免费下载链接】js-yaml JavaScript YAML parser and dumper. Very fast. 项目地址: https://gitcode.com/gh_mirrors/js/js-yaml 在现代JavaScript开发中,配置管理混乱、数据序列化… 2026/7/11 14:53:26
Diva Mod Manager终极指南:3分钟掌握初音未来MOD管理神器 Diva Mod Manager终极指南:3分钟掌握初音未来MOD管理神器 【免费下载链接】DivaModManager 项目地址: https://gitcode.com/gh_mirrors/di/DivaModManager Diva Mod Manager是一款专为《初音未来:Project Diva Mega Mix》玩家设计的图形化MOD管理… 2026/7/11 14:51:25
5分钟搞定Kodi字幕难题:智能字幕插件让你追剧无忧 [特殊字符] 5分钟搞定Kodi字幕难题:智能字幕插件让你追剧无忧 🎬 【免费下载链接】zimuku_for_kodi Kodi 插件,用于从「字幕库」网站下载字幕 项目地址: https://gitcode.com/gh_mirrors/zi/zimuku_for_kodi 还记得那个深夜吗?你刚下载… 2026/7/11 0:00:11
工业信号干扰处理与FOD4216光耦应用实战 1. 工业环境中的信号干扰挑战在工业自动化领域,信号采集的准确性直接关系到整个控制系统的可靠性。典型的工业现场充斥着各种干扰源:大功率电机启停产生的电磁干扰、变频器工作产生的高频噪声、继电器触点火花放电,以及长距离传输引入的共模干… 2026/7/11 0:00:11
OpenHarmony 完整项目工程整合规范 + 模块化分层架构(API23+ 标准企业级结构) 摘要前面系列教程覆盖了 ArkUI 组件、路由、生命周期、本地存储、网络请求、Ability 底层全套基础能力,本篇统一梳理标准工程目录分层、模块化拆分、代码复用规范、全局工具统一管理、项目打包权限配置、常见工程报错统一解决方案,形成可直接用于课程设计… 2026/7/11 0:00:11
6个月转型AI工程师:实战路径与核心技能 1. 项目概述:6个月转型AI工程师的可行性路径在2023年大模型技术爆发的背景下,AI工程师岗位需求同比增长217%(LinkedIn数据)。不同于传统算法工程师需要3-5年培养周期,现代AI工程师更侧重工程化落地能力。我在硅谷科技公… 2026/7/11 14:53:30
TPAFE0808与PIC18F87K22的多通道信号采集方案 1. 项目背景与核心需求在工业自动化、医疗设备和科研仪器等领域,多通道信号采集与系统监测是基础且关键的技术需求。传统方案往往面临通道数量不足、信号调理复杂、系统集成度低等问题。TPAFE0808作为一款8通道模拟前端芯片,与PIC18F87K22微控制器的组合… 2026/7/11 12:30:52
STC3115与PIC18LF26K80构建高精度电池管理系统 1. STC3115与PIC18LF26K80在电池管理系统中的核心价值在现代电子设备中,电池管理系统(BMS)的重要性不亚于设备的核心处理器。STC3115作为一款高精度电池电量监测IC,与PIC18LF26K80微控制器的组合,构成了一个既能精确监控又能智能管理的完整解… 2026/7/8 14:25:08