虚拟内存和物理内存
内存地址的概念
物理地址:物理内存就是真实的内存,CPU的地址线可以直接进行寻址的内存空间大小。比如在32位平台下,寻址的范围是2^32也就是4G,即32位最高4G内存,并且这是固定的。
虚拟地址:为了解决实际内存空间无法满足应用程序而但是的,经常用于容器化技术中,比如一个节点共有64G内存,部署了8个需要16G内存的pod。这时,每个pod都认为自己有16G的实际内存,这一点是通过不断有目的的换入和换出(swap)实现的。这一部分内存就是虚拟内存。
对于32位处理器,虚拟内存空间是4G,即每个pod/程序认为自己有4G内存,64位则更多
每个pod/进程都认为自己得到的内存地址(虚拟内存)是连续的,而实际上,它通常是被分隔成多个物理内存碎片
既然8个16G的pod需要的总内存是远超64G实际存储的,但是又要能够维持它的运行,那部分数据肯定是不能丢的,它其实被存储到了其他地方,例如本地硬盘,或外部磁盘存储器上,在需要时进行数据交换
由于存在两个内存地址,因此一个应用程序从编写到被执行,需要进行两次映射。第一次是映射到虚拟内存空间,第二次时映射到物理内存空间。在计算机系统中,第两次映射的工作是由硬件和软件共同来完成的。承担这个任务的硬件部分叫做存储管理单元MMU,软件部分就是操作系统的内存管理模块了
虚拟内存和物理内存的关联
虚拟内存和物理内存都被分成了大小相等的页,Linux下每个页为4KB。这样虚拟内存和物理内存就都有了页号这个概念,能够通过页号定位到内存中的特定页
虚拟内存中存的不是数据,而是页号+页内偏移量
这时只有再有一个虚拟内存页号与物理内存页号的对应关系,就可以通过虚拟内存找到对应的物理内存位置了。这个对应关系就是页表。程序读取内存时,通过页表和自己持有的虚拟内存页号,找到对应的物理内存页号,再结合记录的偏移量,确定物理内存中实际记录的数据
但是就像在容器化技术中,一个64G的节点部署了8台16G的pod,虚拟内存的页号肯定就比物理内存多,这时候程序在读取内存的时候,就会获得一个“缺页异常”,即申请的数据目前还不在物理内存中,此时CPU是不能工作的,Linux会产生一个hard page fault中断。系统需要从慢速设备(如磁盘)将对应的数据page读入物理内存,同时将一块最少使用的物理内存页,将他们写入慢速设备,然后修改页表映射关系。
在linux中,这个用于额外存储的慢速设备就是交换区SWAP
swap in:产生hard page fault时从磁盘写回到物理内存
swap out:物理内存不够用时把一些物理内存页写入到磁盘
用户空间和内核空间
以一个32位系统为例,一个程序认为自己拥有4G的内存空间,有3G是程序可以访问的,还有1G是只允许操作系统内核访问的,这两部分分别就是用户空间和内核空间,其作用为:
用户空间:低3G字节(从虚拟地址 0x00000000 到 0xBFFFFFFF),提供给程序存储字节的业务数据对应的页号
内核空间:高1G字节(从虚拟地址 0xC0000000 到 0xFFFFFFFF),提供给内核去支持CPU执行一些危险命令
内核态与用户态
其实就是程序运行在哪个地址空间中。运行在用户空间,就说程序是用户态,运行在内核空间,就说程序是内核态
DOS是不区分用户态和内核态的,即程序全部运行在内核态。而linux是区分的,这样提升了系统的稳定性
大部分代码是不具备内核态的能力的,少部分具备,例如NIO中的MappedByteBuffer
评论区