关于程序方面的理解

首先先说几个问题 

死递归是什么?

为什么访问空指针系统会报错?

虚拟内存是什么? 这个和虚拟地址空间有什么区别?

程序是怎么样运行的?

虚拟地址是如何转换到物理地址上的?

先说一下程序是个什么东西?

我理解的程序就是 实现人们需要的一种逻辑 比如玩游戏的时候我们想打一个人 我们需要有这个人而且需要有我们自己 这些就是2个对象 也就是为什么c++是一个面向对象的语言

我们要打一个人我们就可以在我们这个对象里面写一个函数就是打的过程 因此我们满足了我们的逻辑这个程序一运行我们就可以在我的电脑上 我调用这个函数就说明我打了一下

这个逻辑我们可以说就是我们编写好了的代码(以后就说代码了) 我们空空的想肯定是不行的我们得把这个代码给体现出来 显示到电脑上要人能够感受到 那么就得有硬件的支撑

硬件又包括(cpu  ;io(显示器,键盘);内存 等等 有兴趣有钱的可以把电脑拆开看看哈哈)那么编译器就是将我们的代码翻译成硬件能够识别的语言  从而显现出来 

那么现在我们就是讲硬件是如何执行我们的逻辑 cpu就如同人的大脑是负责运算的 比如有一个1+1=2 那么cpu就是处理这个运算的 但是cpu是如何知道这是个1+1 而不是2+2

2+3 2-1呢?这就是我所说的内存 cpu只执行我们物理内存上的代码

一般来说我们的物理内存也就是4G 但是我们的程序可能会有很多 如果一台电脑只能运行一个程序那么多悲催 你想着 你的电脑如果只能玩QQ而不能逛浏览器 不能听歌 不能看电视

就只能聊天多惨 所以所为了防止这样的事情发生 我们引进了虚拟地址空间 也就是说不管三七二十一 先分配地址再说 (ps 这个内存不能说是虚拟内存)这个地址就是虚拟地址空间我们得把这个地址上的东西投影到真正的物理地址(物理内存)上(因为我们是通过地址来找值的)这样代码才能执行也可以同时执行很多个程序因为程序与程序之间互不影响 

(至于有人会说是不是启动了一个程序那么4G不就全部投影上了 那就没有多余的内存来投影下个程序了 不应该全不占用了吗?)

仔细想想是可能会占用全部的内存 但是一般来说不可能全部投影 当然也有例外(想想有些大型一些的有些要规定内存大小cpu的运算 显卡的好坏)这些的确是会把内存占住 但是想想qq才多大 浏览器才多大 而且加载的时候也不是把全部的代码全加载进来而是选择性的加载把那些要用的才加载到物理内存上不然就一直在虚拟地址空间上呆着吧 既然是虚拟的那么也就不占内存

现在开始解释之前的问题死递归是什么?

就是虚拟地址空间里面会分段 比如你的代码的全局变量就放在了.data段上 .text段放着函数的地址 

还有堆栈段 里面就是堆 也就是

大概这样的分布 再底下就是代码的执行了 一些局部变量就要放入栈中 这个栈只有1M-2M左右 所以我们递归调用肯定会有不停的压入很多很多的代码 所以说也就会把这个栈给挤爆 还有malloc申请的堆内存最多也就3G的样子这个就是死递归的由来 就会代码运行就会崩溃

为什么访问空指针系统会报错?

NULL指针其实也有自己的地址 大概就是0x0000这个地址也就在内核空间预留的一小段地址 一旦有人访问这个地址就会报错

虚拟内存是什么? 这个和虚拟地址空间有什么区别?

虚拟地址空间就是程序一运行分配的4g大小的空间 而虚拟内存是当我们真正的物理内存不够了我们去硬盘上找个替代品 来代替内存来处理一下 当然看价格就知道一个40G的固态硬盘400块一个普通的硬盘400g或者4个T才200多 一个内存条4G 就要400块 看价格就知道内存条还是特别贵的 因为贵所以他和cpu交接的速度也就很快  所以说用到虚拟内存了就说明你的物理内存小了

程序是怎么样运行的?

这个简单来说就是我们是上层看不到操作系统如何将虚拟地址空间转化到物理内存上 所以我们只管在虚拟地址空间上 准确的来说我们是通过不断的压栈不断的出栈来的 比如有

int a=10;

int b=20;

int c=a+b;

首先我们把a的地址压入栈 然后压入b的地址 然后我们出栈出b我们就知道b的值然后再出a就知道a的值 通过cpu的计算将c算出来然后 压入c;

计算机就是这样做的

 虚拟地址是如何转换到物理地址上的?

形象的告诉你 逻辑地址 就是你现在打印出来的&变量 线性地址也就是虚拟地址 在linux上可以简单的把逻辑地址当作虚拟地址 虚拟地址 比如32位的地址前10个位是页目录的下标 页目录的地址是放在寄存器里的 页目录的的下标对应的是页表 中间10个位是页表的下标 页表对应的就是页 页表对应的页有32个位 前20个位就是页的地址 后面的12个位放的就是 权限信息 虚拟地址后面12个位放的是偏移量 这个12个位再加下页目录里的对应页表里面存储的32位的前20位 就是真正的物理内存了 可以仔细想想是不是一个页大小是不是4k 这个12位就对应的就是这个页里面的具体位置 

其实说到这也就可以了

下面是具体的

这个是之前写的其实不够完整还可以有补充比如如何转换的   首先我们看逻辑地址 在16位寄存器之后我们有cs(。text) ds(。data) ss(堆栈) 寄存器  逻辑地址代表是段的偏移量 而我们所说的线性地址则表示逻辑地址加上段的偏移量 在寄存器cs ds ss 上然而我们要知道段的起始位置就得在gdtr寄存器上(段描述表项中寻找)而cs ds ss的地址表示的是gdtr的下标 所以我们要找段的起始位置就得找到 gdtr中存的数据 找到之后加上段的偏移量就是 线性地址 再看有没有开启分页也就是寄存器cr0 的最高位pg位是否1 如果是1则开启分页 那么我们就真正进入页映射了 然后我们再看线性地址 线性地址的高10位是表示的页目录的下标 中间10位是表示页表的下标 最后的12位则是物理内存的偏移量 而最开始的页目录的地址存储在 cr3寄存器 下标存的是指针 所以说4*高10位的大小加上cr3里面的地址 就是页目录的地址 但是由于页表项的大小是4k那么就只取高20位便找到了 页表的地址 同理找到了物理地址页面再加上12位的偏移量便就是真正的物理地址了啦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值