You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

虚拟/逻辑地址生成主体、作用及相关技术疑问咨询

关于虚拟地址、相对地址的疑问解答

1. printf输出的虚拟地址是谁生成的?

不是加载器单独完成的,是操作系统、加载器、CPU三者配合的结果。编译器编译出的是带重定位信息的目标文件或位置无关代码(PIC),加载器在加载程序时,会根据操作系统分配的虚拟地址空间,完成重定位操作——把代码里的相对地址绑定到具体的虚拟地址上。程序运行时,CPU执行指令时使用的就是这些虚拟地址,printf用%p输出的就是这个最终地址。

2. 为什么需要虚拟地址,只用相对地址+MMU基址偏移不行?

早期确实有基址+偏移的内存管理模式(比如实模式的分段),但这种方式存在诸多硬伤:

  • 隔离性差:进程若误修改基址寄存器,就能直接访问其他进程的物理内存,极易导致系统崩溃。
  • 内存碎片化严重:物理内存必须连续分配给进程,大程序可能因找不到连续物理块无法运行。
  • 地址空间受限:比如16位系统只能访问1MB内存,无法利用更大的硬件内存资源。

虚拟地址的优势刚好解决这些问题:

  • 它是操作系统通过页表/段表给进程分配的独立地址空间,每个进程的虚拟空间相互隔离,MMU负责虚拟地址到物理地址的转换,进程无法直接修改页表,安全性得到保障。
  • 虚拟地址可以映射到不连续的物理内存块,操作系统通过页表将这些分散的物理内存“拼接”成连续的虚拟空间,彻底解决碎片化问题。
  • 支持内存交换(把不常用的内存页换到磁盘),能充分利用硬件内存,突破物理内存的限制。

3. 虚拟地址如何让进程产生独占连续内存的错觉?

加载器的核心工作之一,是把程序的代码段、数据段等模块,映射到操作系统分配的虚拟地址空间的连续区域——而这些虚拟地址对应的物理内存,完全可以是分散的。

举个例子:进程A的虚拟地址0x1000-0x2000可能对应物理内存的0x5000-0x6000,虚拟地址0x2000-0x3000对应物理内存的0x9000-0xA000,但在进程A的视角里,自己的内存就是从0x1000开始的连续区域。

另外,不同进程完全可以拥有相同的虚拟地址,因为每个进程的页表是独立的,相同的虚拟地址会被MMU映射到不同的物理内存,彼此不会产生冲突。比如进程A和进程B的虚拟地址0x400000,可能分别对应物理内存的0x123000和0x456000,互相不影响。

4. 为什么网上说“虚拟地址由CPU生成”?

这句话并没有错,只是表述角度不同:

  • 操作系统负责规划虚拟地址空间、维护页表,但程序运行时,CPU执行指令(取指令、访问变量等)时发出的地址就是虚拟地址,而MMU本身就是CPU的一部分,负责完成虚拟地址到物理地址的转换。
  • 简单来说,操作系统是“规则制定者”,CPU是“实际执行者”。从硬件运行的角度看,程序运行时产生和使用虚拟地址的是CPU硬件,所以网上的说法是从这个层面出发的,和“操作系统负责分配虚拟地址”并不矛盾。

内容的提问来源于stack exchange,提问作者Allexj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:40:11