当前位置: 首页 > news >正文

进程的内存映像,只读区,可读写区,堆,共享库,栈详解

我们把一个进程的虚拟地址空间想象成一栋专门为它建造的摩天大楼

  • 虚拟地址空间:这栋摩天大楼的设计图纸。在32位系统上,图纸上规划了从0层到大约40亿层(4GB)的巨大空间。每个进程都拿到一份一模一样的图纸,它们都以为自己独占了整栋大楼。
  • 物理内存:现实世界中真正可用的建筑材料。所有进程的“大楼”实际上都是用这些有限的材料搭建的。

摩天大楼的楼层规划(从低地址到高地址)

这栋4GB高的大楼,被严格地分成了两个大区:用户区(低3GB) 和 内核区(高1GB)

内核区 (Kernel Space) - “顶层豪华总统套房” (高地址区域)
  • 位置:大楼的最顶层,大约从3GB到4GB的位置。
  • 住户操作系统内核
  • 存放内容
    • 进程的“身份证” (PCB):每个租户(进程)的个人档案都存放在这里,由大楼管理员(OS)统一保管。
    • 大楼的“管理规定” (OS代码):比如“租户调度规则”、“安保条例”等,都存放在这里。
    • 大楼的“总地图” (页表):记录了每个租户的“设计图纸”是如何映射到“现实建材”上的。
  • 权限戒备森严。普通租户(用户进程)绝对禁止入内。只有在需要请求管理员服务时(通过系统调用),才能在管理员的陪同下进入一小部分指定区域。

用户区 (User Space) - “租户的私人生活空间” (低地址区域)

这是分配给每个进程自由使用的区域。它也被精心划分成了几个功能区。

1. 只读区(代码段 .text + 只读数据段 .rodata) - “图书馆和展览馆”
  • 位置:用户区的最底层。
  • 存放内容
    • 代码段 (.text): 你写的C语言代码被编译成的机器指令(程序的“说明书”),就存放在这里。这些指令是规定好的,运行时不能被修改。
    • 只读数据段 (.rodata): 存放常量。比如C语言里用 const 关键字定义的全局变量,或者字符串字面量(如"Hello, World!")。它们就像展览馆里的展品,只能看,不能摸(不能修改)。
  • 宏定义 vs. const常量
    • #define PI 3.14:这只是一个“文本替换”的宏。在预编译阶段,代码里所有的PI都会被直接换成3.14。它不会在内存中单独占据一个格子,而是融入了指令之中。
    • const float pi = 3.14;:这定义了一个真正的常变量。系统会为pi在只读数据区分配一个格子,并把3.14存进去。你可以获取它的地址,但不能修改它的值。
2. 可读写数据区(数据段 .data + .bss段) - “储藏室”
  • 位置:只读区的上方。
  • 存放内容:那些在程序整个生命周期内都存在的、且可以被修改的变量。
    • 数据段 (.data): 存放已初始化的全局变量和静态变量。比如 int global_var = 10;。程序启动时,这个10就会被加载到这里。
    • BSS段 (.bss): 存放未初始化的全局变量和静态变量。比如 static int static_var;。为了节省可执行文件的大小,这些变量的值(默认为0)不会被存在文件里,只是记录了需要多大的空间。程序启动时,操作系统会在这里清出一片内存,并全部填充为0。
  • 特点:这片区域的大小在程序加载时就固定了,运行时不会改变。
3. 堆 (Heap) - “可自由搭建的乐高区”
  • 位置:数据区的上方。
  • 生长方向:从低地址向高地址增长。
  • 存放内容:由程序员手动管理的内存。在C语言中,通过 malloc() 申请的内存就在堆上;通过 free() 释放。
  • 特点:大小动态变化。你需要多少,就申请多少。忘了释放,就会造成内存泄漏。堆是程序中最灵活、也最容易出问题的地方。
4. 共享库 (Shared Libraries) - “公共设施层”
  • 位置:在堆和栈之间的一大片区域。
  • 存放内容:存放一些系统提供的、多个进程可以共享的库函数代码。比如 printfscanf 等函数的机器指令。
  • 特点:为了节省内存,这些公共的库函数在物理内存中可能只存在一份,但被映射到了多个进程的虚拟地址空间中。
5. 栈 (Stack) - “临时工作间”
  • 位置:用户区的最顶层。
  • 生长方向:从高地址向低地址增长。这种设计可以使堆和栈有最大的发展空间,只要它们不“撞车”就行。
  • 存放内容:与函数调用相关的一切。
    • 局部变量:在函数内部定义的变量。
    • 函数参数:调用函数时传递的参数。
    • 返回地址:函数执行完后,应该跳回到哪里继续执行。
  • 特点自动管理。调用一个函数时,系统会自动在栈顶“压入”一块内存(称为一个栈帧)来存放这个函数相关的所有数据。当函数返回时,这块内存会被自动“弹出”并销毁。如果函数调用嵌套太深(比如无限递归),栈会不停地向低地址增长,最终可能会用尽所有空间,导致栈溢出 (Stack Overflow)

必会题与详解

题目:给定以下C语言代码,请指出变量g_varg_uninit_varPIc_vars_varl_var 以及 p_var 所指向的内存,分别存储在进程内存映像的哪个区域?

#include <stdio.h>
#include <stdlib.h>#define PI 3.14159const int c_var = 10;
int g_var = 20;
int g_uninit_var;void func() {int l_var = 40;printf("Local variable: %d\n", l_var);
}int main() {static int s_var = 30;int *p_var = (int*)malloc(sizeof(int));*p_var = 50;func();free(p_var);return 0;
}

答案详解

  • g_var (全局已初始化变量):存储在 数据段 (.data)。它在程序整个生命周期都存在,并且有初始值。

  • g_uninit_var (全局未初始化变量):存储在 BSS段 (.bss)。它也在整个程序生命周期存在,但没有初始值,程序加载时会被初始化为0。

  • PI (宏定义常量)不存储在内存的任何区域。它是一个宏,在预编译阶段,代码中所有出现PI的地方都会被直接替换为文本3.14159。它最终会成为CPU指令的一部分(比如 mov rax, 3.14159)。

  • c_var (const全局变量):存储在 只读数据段 (.rodata)。它是一个常量,程序运行时不能被修改。

  • s_var (静态局部变量):存储在 数据段 (.data)。虽然它定义在main函数内部,但static关键字改变了它的生命周期,使其与程序的生命周期一样长。因为它有初始值,所以存放在.data段。

  • l_var (局部变量):存储在 栈 (Stack) 上。它是func函数的局部变量,当func被调用时,l_varfunc的栈帧中被创建;当func返回时,它随着栈帧的销毁而被释放。

  • p_var 所指向的内存:变量p_var本身是一个指针,它是一个局部变量,所以p_var这个指针变量本身存储在栈 (Stack) 上。但是,它所指向的那块通过malloc分配的、大小为sizeof(int)的内存,是存储在 堆 (Heap) 上的。

http://www.lryc.cn/news/588763.html

相关文章:

  • 【机器学习基础【5】】Python数据科学三件套:从数据创建到处理再到可视化实战
  • 链表的 哑结点的本质
  • 排序算法实战(上)
  • 经典排序算法之希尔排序
  • 解锁Python爬虫:数据获取与清洗的进阶指南
  • 深入浅出 RabbitMQ-核心概念介绍与容器化部署
  • Zabbix钉钉告警
  • 如何将华为文件传输到电脑
  • C++ - 仿 RabbitMQ 实现消息队列--muduo快速上手
  • 每日钉钉API探索:chooseUserFromList灵活选取自定义联系人
  • 变更缓冲池简介
  • Git分支管理与工作流详解
  • STL的一些知识点
  • Java-特殊文件、日志技术
  • RTDETR融合CFFormer中的FeatureCorrection_s2c模块
  • 下一代防火墙-web防护
  • Android弹窗
  • 2025牛客暑期多校训练记录
  • Ubuntu 22.04 安装 mysql-server服务端
  • Gartner《JavaScript: Top Use Cases, Frameworks and Architecture Constraints》学习心得
  • Java基础教程(009): Java 的封装
  • 约数之和其中数论的作用
  • 【前端】Vue 3 页面开发标准框架解析:基于实战案例的完整指南
  • SpringBoot 项目搭建的 4 种常用方式,从入门到实践
  • Android 多语言适配(I18n)
  • ICCV 2025满分论文:一个模型实现空间理解与主动探索大统一
  • 原型继承(prototypal inheritance)的工作原理
  • AOP简化MyBatis分页:高效自动化方案
  • 解决 Node.js 版本不兼容问题:深入理解 `yarn install --ignore-engines`
  • 【前后端】Node.js 模块大全