深入理解 Linux 内核:虚拟地址空间与物理内存的映射关系

wufei123 2024-06-04 阅读:11 评论:0
显存映射 化学显存合称为寻址,动态随机访问显存(DRAM)。只有内核才可以直接访问数学显存。 Linux内核给每位进程都提供了一个独立的虚拟地址空间,但是这个地址空间是连续的。这样,进程就可以很便捷地访问显存,更准确地说是访问虚拟显存。虚拟...

显存映射

化学显存合称为寻址,动态随机访问显存(DRAM)。只有内核才可以直接访问数学显存。

Linux内核给每位进程都提供了一个独立的虚拟地址空间,但是这个地址空间是连续的。这样,进程就可以很便捷地访问显存,更准确地说是访问虚拟显存。虚拟地址空间的内部又被分为内核空间和用户空间两部份。

linux 用户分配空间_linux磁盘分配空间_linux分配用户权限

进程在用户态时,只能访问用户空间显存;只有步入内核态后,才可以访问内核空间显存。其实每位进程的地址空间都包含了内核空间,但这种内核空间,虽然关联的都是相同的化学显存,也就是共享动态链接库、共享显存等。当进程切换到内核态后,就可以很便捷地访问内核空间显存。

并不是所有的虚拟显存就会分配化学显存,只有这些实际使用的虚拟显存才分配化学显存,但是分配后的化学显存,是通过显存映射来管理的。显存映射,虽然就是将虚拟显存地址映射到化学显存地址。为了完成显存映射,内核为每位进程都维护了一张页表,记录虚拟地址与化学地址的映射关系。

linux磁盘分配空间_linux分配用户权限_linux 用户分配空间

页表实际上储存在CPU的显存管理单元MMU中,这样,正常情况下,处理器就可以直接通过硬件,找出要访问的显存。而当进程访问的虚拟地址在页表中查不到时,系统会形成一个缺页异常,步入内核空间分配化学显存、更新进程页表,最后再返回用户空间,恢复进程的运行。

CPU上下文切换中的TLB(TranslationLookasideBuffer,转译后备缓冲器)是MMU中页表的高速缓存。因为进程的虚拟地址空间是独立的linux是什么系统,而TLB的访问速率又比MMU快得多,所以,通过降低进程的上下文切换,降低TLB的刷新次数,就可以提升TLB缓存的使用率,从而提升CPU的显存访问性能。

MMU规定了一个显存映射的最小单位,也就是页,一般是4KB大小。这样,每一次显存映射,都须要关联4KB或则4KB整数倍的显存空间。

4KB大小的页,会造成整个页表会显得十分大,例如32位系统4GB/4KB=100多万个页表项。为了解决页表项过多的问题,Linux提供了两种机制,也就是多级页表和大页(HugePage)。

linux分配用户权限_linux 用户分配空间_linux磁盘分配空间

多级页表就是把显存分成区块来管理,将原先的映射关系改成区块索引和区块内的偏斜。因为虚拟显存空间一般只用了极少一部份,这么,多级页表就只保存那些使用中的区块,这样就可以大大地减低页表的项数。Linux用四级页表来管理显存页,虚拟地址被分为5个部份,前4个表项用于选择页,而最后一个索引表示页内偏斜。

linux 用户分配空间_linux磁盘分配空间_linux分配用户权限

大页,就是比普通页更大的显存块,常见的大小有2MB和1GB。大页一般用在使用大量显存的进程上,例如Oracle、DPDK等。

通过这种机制,在页表的映射下,进程就可以通过虚拟地址来访问数学显存了。

虚拟显存空间分布

最上方的是内核空间,下方的是用户空间显存,用户空间又被分成多个不同的段

linux磁盘分配空间_linux分配用户权限_linux 用户分配空间

用户空间显存,从低到高分别是5种不同的显存段

1、只读段,包括代码和常量等

linux磁盘分配空间_linux 用户分配空间_linux分配用户权限

2、数据段,包括全景变量等

3、堆,包括动态分配的显存,从低地址开始向下下降

4、文件映射段,包括动态库,共享显存等,从高地址开始向上下降

5、栈,包括局部变量和函数调用的上下文等,栈的大小是固定的,通常是8M

这5个显存段中,堆和文件映射的显存是动态分配的,例如使用C标准库的malloc或mmap(),就可以分别在堆和文件映射段动态分配显存。64位系统的显存分布也是类似的,只是显存空间要大的多

显存分配与回收

malloc()是C标准库提供的显存分配函数,对应到系统调用上,有两种实现方法,即brk()和mmap()。

linux磁盘分配空间_linux 用户分配空间_linux分配用户权限

对小块显存(大于128K),C标准库使用brk()来分配,也就是通过联通堆顶的位置来分配显存。这种显存释放后并不会立即归还系统,而是被缓存上去,这样就可以重复使用。

linux磁盘分配空间_linux分配用户权限_linux 用户分配空间

对大块显存(小于128K),则直接使用显存映射mmap()来分配,也就是在文件映射段找一块空闲显存分配出去。

这两种方法的异同点:

brk()方法的缓存,可以降低缺页异常的发生,提升显存访问效率。不过,因为这种显存没有归还系统,在显存工作忙碌时,频繁的显存分配和释放会导致显存碎片。

mmap()方法分配的显存,会在释放时直接归还系统,所以每次mmap就会发生缺页异常。在显存工作忙碌时,频繁的显存分配会造成大量的缺页异常,使内核的管理负担减小。这也是malloc只对大块显存使用mmap的诱因。

须要注意的是:当这两种调用发生后,虽然并没有真正分配显存。这种显存,都只在首次访问时才分配,也就是通过缺页异常步入内核中,再由内核来分配显存。

整体来说,Linux使用伙伴系统来管理显存分配。上面我们谈到过,这种显存在MMU中以页为单位进行管理,伙伴系统也一样linux漏洞扫描,以页为单位来管理显存,而且会通过相邻页的合并,降低显存碎片化(例如brk方法导致的显存碎片)。

但在实际系统运行中,会有大量比页还小的对象,如不到1K,倘若为它们也分配单独的页,会浪费大量的显存,那该如何分配显存呢?

在用户空间linux 用户分配空间,malloc通过brk()分配的显存,在释放时并不立刻归还系统,而是缓存上去重复借助。

在内核空间,Linux则通过slab分配器来管理小显存。你可以把slab看成建立在伙伴系统上的一个缓存,主要作用就是分配并释放内核中的小对象。

linux 用户分配空间_linux磁盘分配空间_linux分配用户权限

显存回收:对显存来说,假如只分配而不释放,还会导致显存泄露,甚至会用尽系统显存。所以,在应用程序用完显存后,还须要调用free()或unmap(),来释放那些不用的显存。其实,系统也不会任由某个进程用完所有显存。在发觉显存紧张时,系统还会通过一系列机制来回收显存,例如下边这三种形式:

(1)回收缓存,例如使用LRU(LeastRecentlyUsed)算法,回收近来使用最少的显存页面。

(2)回收不常访问的显存,把不常用的显存通过交换分区(Swap)直接讲到c盘中。Swap虽然就是把一块c盘空间当作显存来用。它可以把进程暂时不用的数据储存到c盘中(这个过程称为换出),当进程访问那些显存时,再从c盘读取这种数据到显存中(这个过程称为换入)。Swap把系统的可用显存变大了,但一般只在显存不足时,就会发生Swap交换,而且因为c盘读写的速率远比显存慢,Swap会造成严重的显存性能问题。

(3)杀害进程,显存紧张时系统就会通过OOM(OutofMemory,内核的一种保护机制),直接杀掉占用大量显存的进程.。OOM监控进程的显存使用情况,但是使用oom_score为每位进程的显存使用情况进行评分:

一个进程消耗的显存越大,oom_score就越大;

一个进程运行占用的CPU越多,oom_score就越小。

这样,进程的oom_score越大,代表消耗的显存越多,也就越容易被OOM杀害,进而可以更好保护系统。

其实,为了实际工作的须要,管理员可以通过/proc文件系统,自动设置进程的oom_adj,因而调整进程的oom_score。oom_adj的范围是[-17,15],数值越大,表示进程越容易被OOM杀害;数值越小,表示进程越不容易被OOM杀害,其中-17表示严禁OOM。如用下边的命令,你就可以把sshd进程的oom_adj调小为-16,这样,sshd进程就不容易被OOM杀害。

echo-16>/proc/$(pidofsshd)/oom_adj

linux磁盘分配空间_linux 用户分配空间_linux分配用户权限

linux磁盘分配空间_linux 用户分配空间_linux分配用户权限

buffer和cache

free命令中buffer和cache都表示缓存,但用途不一样

1、Buffer,是内核缓冲区用到的显存,对应的是/proc/meminfo中的Buffer值

2、Cache,是内核页缓存和Slab用到的显存,对应的是/proc/meminfo中的Cache和SReclaimable之和

简单来说,Buffer是对c盘数据的缓存,而Cache是文件数据的缓存,它们既会用在读恳求中,也会用在写恳求中。

cache(缓存)从CPU角度考虑,是为了提升cpu和显存之间的数据交换速率而设计的,比如平时看到的一级缓存、二级缓存、三级缓存。cpu在执行程序所用的指令和读数据都是针对显存的,也就是从显存中取得的。因为显存读写速率慢,为了提升cpu和显存之间数据交换的速率,在cpu和显存之间降低了cache,它的速率比显存快linux 用户分配空间,而且造价高,又因为在cpu内不能集成太多集成电路,所以通常cache比较小,之后intel等公司为了进一步提升速率,又降低了二级cache,甚至五级cache,它是按照程序的局部性原理而设计的,就是cpu执行的指令和访问的数据常常在集中的某一块,所以把这块内容装入cache后,cpu就不用在访问显存了,这就提升了访问速率。其实若cache中没有cpu所须要的内容,还是要访问显存的。

从显存读取与c盘读取角度考虑,cache可以理解为操作系统为了更高的读取效率,更多的使用显存来缓存可能被再度访问的数据。

缓冲(buffers)是为了提升显存和硬碟(或其他I/O设备)之间的数据交换的速率而设计的。把分散的写操作集中进行,降低c盘碎片和硬碟的反复寻道,因而提升系统性能。linux有一个守护进程定期清空缓冲内容(即写入c盘),也可以通过sync命令自动清空缓冲。

简单来说,buffer是即即将被写入c盘的,而cache是被从c盘中读下来的。buffer是由各类进程分配的,被用在如输入队列等方面。一个简单的反例如某个进程要求有多个数组读入,在所有数组被读入完整之前,进程把原本读入的数组置于buffer中保存。

cache常常被用在c盘的I/O恳求上,假如有多个进程都要访问某个文件,于是该文件便被弄成cache以便捷上次被访问,这样可提升系统性能。

以上就是深入理解 Linux 内核:虚拟地址空间与物理内存的映射关系的详细内容,更多请关注知识资源分享宝库其它相关文章!

版权声明

本站内容来源于互联网搬运,
仅限用于小范围内传播学习,请在下载后24小时内删除,
如果有侵权内容、不妥之处,请第一时间联系我们删除。敬请谅解!
E-mail:dpw1001@163.com

分享:

扫一扫在手机阅读、分享本文

发表评论
热门文章
  • 华为 Mate 70 性能重回第一梯队 iPhone 16 最后一块遮羞布被掀

    华为 Mate 70 性能重回第一梯队 iPhone 16 最后一块遮羞布被掀
    华为 mate 70 或将首发麒麟新款处理器,并将此前有博主爆料其性能跑分将突破110万,这意味着 mate 70 性能将重新夺回第一梯队。也因此,苹果 iphone 16 唯一能有一战之力的性能,也要被 mate 70 拉近不少了。 据悉,华为 Mate 70 性能会大幅提升,并且销量相比 Mate 60 预计增长40% - 50%,且备货充足。如果 iPhone 16 发售日期与 Mate 70 重合,销量很可能被瞬间抢购。 不过,iPhone 16 还有一个阵地暂时难...
  • 酷凛 ID-COOLING 推出霜界 240/360 一体水冷散热器,239/279 元

    酷凛 ID-COOLING 推出霜界 240/360 一体水冷散热器,239/279 元
    本站 5 月 16 日消息,酷凛 id-cooling 近日推出霜界 240/360 一体式水冷散热器,采用黑色无光低调设计,分别定价 239/279 元。 本站整理霜界 240/360 散热器规格如下: 酷凛宣称这两款水冷散热器搭载“自研新 V7 水泵”,采用三相六极马达和改进的铜底方案,缩短了水流路径,相较上代水泵进一步提升解热能力。 霜界 240/360 散热器的水泵为定速 2800 RPM 设计,噪声 28db (A)。 两款一体式水冷散热器采用 27mm 厚冷排,...
  • 惠普新款战 99 笔记本 5 月 20 日开售:酷睿 Ultra / 锐龙 8040,4999 元起

    惠普新款战 99 笔记本 5 月 20 日开售:酷睿 Ultra / 锐龙 8040,4999 元起
    本站 5 月 14 日消息,继上线官网后,新款惠普战 99 商用笔记本现已上架,搭载酷睿 ultra / 锐龙 8040处理器,最高可选英伟达rtx 3000 ada 独立显卡,售价 4999 元起。 战 99 锐龙版 R7-8845HS / 16GB / 1TB:4999 元 R7-8845HS / 32GB / 1TB:5299 元 R7-8845HS / RTX 4050 / 32GB / 1TB:7299 元 R7 Pro-8845HS / RTX 2000 Ada...
  • python中def什么意思

    python中def什么意思
    python 中,def 关键字用于定义函数,这些函数是代码块,执行特定任务。函数语法为 def (参数列表)。函数可以通过其名字和圆括号调用。函数可以接受参数作为输入,并在函数体中使用参数名访问。函数可以使用 return 语句返回一个值,它将成为函数调用的结果。 Python 中 def 关键字 在 Python 中,def 关键字用于定义函数。函数是代码块,旨在执行特定任务。 语法 def 函数定义的语法如下: def (参数列表): # 函数体 示例 定义...
  • python中int函数的用法

    python中int函数的用法
    int() 函数将值转换为整数,支持多种类型(字符串、字节、浮点数),默认进制为 10。可以指定进制数范围在 2-36。int() 返回 int 类型的转换结果,丢弃小数点。例如,将字符串 "42" 转换为整数为 42,将浮点数 3.14 转换为整数为 3。 Python 中的 int() 函数 int() 函数用于将各种类型的值转换为整数。它接受任何可以解释为整数的值作为输入,包括字符串、字节、浮点数和十六进制表示。 用法 int(object, base=10) 其中...