23|内存地址空间:程序中地址的三种产生方式
LMOS
你好,我是 LMOS。
前面我们一起探讨了 RISC-V 芯片,设计和实现了一个迷你 CPU。之后还深入研究了 CPU 上面运行的语言和指令系统,它们是构成程序的重要要素。依托于芯片和语言、指令,我们就可以编写和执行程序了。
不过我们开发应用的时候,还有个打交道最频繁的模块——内存。很多工程问题你不懂内存,就会举步维艰。你也许觉得内存知识太难了,不但关联知识又多又散乱,而且深挖下去感觉没有尽头。但计算机的硬核基础,内存是必修关卡,只要你跟住我的节奏坚持下来,一定可以把内存的本质、内存系统的来龙去脉都弄明白,一起加油。
CPU 如何访问内存
CPU 怎么访问内存?我们回想一下,之前讲过的高级语言和低级语言转化过程。
我们先思考一下,C 语言把我们写出来的变量和函数都转换成了什么呢?如果记不太清了,可以回顾第十五节课。没错,C 语言把变量名和函数名都转换成了汇编语言里的标号,而汇编语言的标号,就是机器更好理解的符号。符号具体包括符号类型、符号名称和符号地址这几个属性。其中,符号地址是由一个叫链接器的东西生成的。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了内存地址空间的概念及程序中地址的产生方式。首先,文章介绍了CPU通过内存地址来访问内存,强调了内存地址本质上是一个整数数据,代表了一个内存单元的索引号。其次,通过代码示例和链接脚本的分析,详细阐述了程序代码的地址是如何产生的,包括链接器的工作和程序重定位的过程。此外,文章还介绍了程序中地址的三种产生方式:链接器、直接定义和动态分配内存。另外,文章还涉及了物理地址空间和虚拟地址空间的概念,以及虚拟地址转换成物理地址的过程。总体而言,本文通过清晰的语言和丰富的例子,帮助读者深入理解了内存地址空间的相关概念,为读者快速了解内存地址空间提供了有益的指导。 文章通过深入探讨内存地址空间的概念及程序中地址的产生方式,帮助读者深入理解了内存地址空间的相关概念。首先,文章介绍了CPU通过内存地址来访问内存,强调了内存地址本质上是一个整数数据,代表了一个内存单元的索引号。其次,通过代码示例和链接脚本的分析,详细阐述了程序代码的地址是如何产生的,包括链接器的工作和程序重定位的过程。此外,文章还介绍了程序中地址的三种产生方式:链接器、直接定义和动态分配内存。另外,文章还涉及了物理地址空间和虚拟地址空间的概念,以及虚拟地址转换成物理地址的过程。总体而言,本文通过清晰的语言和丰富的例子,为读者提供了有益的指导,帮助他们快速了解内存地址空间的相关概念。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《计算机基础实战课》,新⼈⾸单¥68
《计算机基础实战课》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(10)
- 最新
- 精选
- 苏流郁宓操作系统安装会给定一个最低内存条存储要求,实际上只要过了这个要求,内存条容量大小操作系统不怎么关心,反正MMU完事 通过原子锁等功能,来维护数据一致性,监控进程/线程。至于软件需求,那好办,通过时间轮换原则,每个线程跑一会就换另一个的! 这也导致一个问题,如果线程过多,那么排队等待时间就会变长!像大型游戏厂商对cpu性能及内存条和显存容量都有要求,也就是帮cpu减负(可以通过显卡芯片完成的就尽量少用cpu,还有驻存在内存条上的数据交换时间总好过内存条与硬盘交换数据) 在大型游戏运行时,显卡驱动也在运行(加载在内存条上,帮助cpu完成部分数据分流给显卡芯片),这也是软硬件方式优化MMU效率的一个案例!
作者回复: 是的 正确
2022-09-17归属地:湖北7 - TableBear连接器使用的地址是虚拟内存地址。物理内存地址要在发起访存操作之后通过MMU单元进行转换才能得到(这个过程设计页表和TLB等机制)。如果虚拟内存地址还未跟物理内存地址绑定,此时还会发生缺页异常陷入内核进行物理内存分配。
作者回复: 是的
2022-09-16归属地:湖北25 - 功夫熊猫只能是虚拟内存,如果用的物理内层就很麻烦,没有可扩展性和可移植性了,而且如果直接操作物理内存,那对应程序员的要求就不是CRUD了。虚拟内存就是那句经典的计算机的话:“计算机什么问题都可以靠增加一层中间层来解决的”
作者回复: 哈哈是的
2022-10-07归属地:湖北3 - 苏流郁宓链接器用的是虚拟内存地址(就不用关心是不是和物理设备地址覆盖)使用时通过操作系统内核加载到物理地址上,操作系统通过进程/线程进行管理! MMU地址转换功能,在保护模式下运行(尽可能避免因虚拟地址相同而导致的数据覆盖) 32位内存应为0到0xefffffff 那么问题来了,对普通程序而言,有虚拟地址方便!但对操作系统开发者而言,恐怕还是得清楚设备地址吧?这个设备地址应该有个标准吧?这样操作系统本身数据才能不与物理设备地址冲突! 如果设备地址的标准不一,预估cpu应该按照设备地址寻址优先原则(允许覆盖),这也估计是为啥操作系统保护模式内核在高位的一个原因吧?(这样,即使不知新的设备地址(假如设备开发商不通知操作系统开发商)只要内核在高位,大不了重新引导程序加载在空的内存空间上的)
作者回复: 是的
2022-09-17归属地:湖北1 - LockedX链接器使用的是虚拟地址,如果使用物理地址那么链接的过程将及其复杂并且物理地址用完了就不能再编译,这显然是不行的。
作者回复: 是的
2022-09-16归属地:湖北1 - peter请教老师几个问题啊: Q1:“设备寄存器”有哪些?只知道CPU有寄存器,难道CPU之外的设备也有寄存器? Q2:“sw_ins((unsigned int)&word, 0);”,调用sw_ins的时候传入了参数,但sw_ins函数的定义中并没有参数啊。 Q3:代码中动态分配的内存是怎么确定地址的?此时程序已经运行,链接器无法参与了。
作者回复: Q1:很多设备都有自己的寄存器
2022-09-16归属地:湖北31 - 温雅小公子手动分配和动态分配的地址也是虚拟地址吗?
作者回复: 是的 都是虚拟
2022-11-06归属地:湖北 - 苏流郁宓cpu给定低16位(64kb内的)可做为端口,物理设备开发商可以通过端口方式直接与cpu沟通(可绕过操作系统,不需要操作系统分配地址,但估计会引发中断方式来被操作系统知悉?)也可以通过设备软件加载在内存上通过进程/线程,来与cpu沟通(需要操作系统分配地址)
作者回复: 嘿嘿 你真聪明
2022-09-17归属地:湖北 - lji当然了,除了这种方式,你可以在程序代码中直接给出一个地址,代码如下:int main(){ //把整数0x20000强制转换为int类型的指针 int *p = (int*)0x20000; *p = 0; //动态分配一个int类型大小的内存空间,其首地址返回给addr指针 void* addr = malloc(sizeof(int)); return 0;}这段代码就是让 p 直接指向 0x20000 地址,然后向这个地址上写入 0。不过这个操作极其危险,除非你确切地知道自己在干什么,因为 0x20000 可能是其它重要数据,也可能不是真正的内存单元,而是设备寄存器,更可能什么也没有,即这个地址没有连接任何有效设备。 请教一下,关于上述的文章内容,代码编译后运行在常见的操作系统下,不是必须通过虚拟内存来映射到主存,这段内容可否理解成:我强行让 MMU 把一个虚拟地址转成物理地址,转换后的地址不可控制,然后覆盖新的变量后可能发生异常。2023-06-15归属地:浙江
- tony老师,您好,请教一个问题;malloc 分配一个内存地址A以后,然后free A,此时访问A程序一定会崩溃。这个崩溃是谁触发的呢?cpu?还是libc的ptmalloc,还是操作系统? 调用malloc时,ptmalloc会从系统中已经申请的地址空间中,分配一段虚拟地址,然后把首地址返回。free时,应该是标记了以该地址为首的区域没有人使用了。此时再来访问这个地址时,cpu mmu模块会转换为物理地址(如果没有找到该物理地址,应该会产生缺页终端,加载页并与虚拟地址绑定在一起);按照这个逻辑,访问这个地址应该不会崩溃呢?谢谢。2022-12-15归属地:上海
收起评论