0. 你的程序是怎么用内存的
introduction
设想一个场景, 你有一个笔记本, 有很多页, 但是这个笔记本要同时给好几门课一起用. 怎么办呢? 你决定每一页要么只记语文, 要么只记数学. 于是造成了第一页语文, 第二页语文, 第三页数学, 第四页语文... 这样的现象. 然后你决定在封面上写个目录, 内容如下:
语文:
第一页 = 笔记本第一页
第二页 = 笔记本第二页
第三页 = 笔记本第四页
数学:
第一页 = 笔记本第三页
...
某天你再上语文课的时候, 你就想着我要去"语文第三页", 查查目录, 翻到笔记本第四页, 就能看到你想看的笔记. 这样你就可劲往后用就行了, 只要每用一页在目录上记录下来就行了.
对应到计算机里
[协调物理内存的使用] 对应到计算机里, 这个笔记本就是你的物理内存, 一大块 物理内存 要给好多个进程大家一起用, 进程每次搞一页来用. 语文以为的第三页, 代表 虚拟地址, 语文第三页对应着笔记本的第四页, 代表 物理地址. 那个用作映射关系的对照表就是页表. 所有语文页形成的空间, 叫虚拟内存空间, 我们已经看到了, 这样做能协调大家一起使用一整块物理内存
[防止乱访问] 我们都知道指针打印出来是一个地址 0x001 这样的形式, 那么现在假设你现在想 dereference 一个指针, 我们是不是直接去物理内存里名为 0x001 的位置上取出内容? 不是的, 这个地址也是虚拟地址, 如果真让你用物理地址取内容, 岂不是你就可以随便读别人程序里的数据了? 因此虚拟地址还能防止你内存乱用乱改.
[内存使用效率加强了] 最后, 你以为你用的都是连续内存, 实际上你使用的内存页零零散散的分布在不同的物理页上, 这说明什么? 说明你对于碎片化的内存运用能力加强了
内存用完了怎么办
想一个问题, 我们真的有那么多内存给你用吗? 如果大家一起用, 然后电脑上的4G内存给你们用完了怎么办? 这种时候我们继续刚刚的虚拟地址那一套, 既然是虚拟地址, 我就可以给你分配一大堆, 想想Go语言分配内存的时候是不是有一个叫 arena 区, 那个我印象里是几百G的水平. 我们不是真的有这么多给你, 我们只是让你觉得你有这么多.
然后现在, 4G真的用完了, 接下来怎么办呢? 我们把其中一部分转移到硬盘(磁盘)上, 腾出来些空位, 让你可以继续用. 这样直接会导致一个问题: 被转移的那个人要用的时候, 发现他要的东西, 可能在内存里, 也可能就不在内存里. 这样就产生了一个 命中 / 不命中 的概念. 如果现在是不命中, 那就是我们常说的缺页, 需要去磁盘里给加载回来, 常用的换页方法有:
LRU, 最近未使用, 导致一个很热, 但是只是最近未使用的被换走
LFU, 最少被使用, 导致一个刚刚被加载出来, 还有很高的复用可能的页, 被换走
Last updated
Was this helpful?