⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux-+

📁 linux下内存管理的文章 很长
💻
📖 第 1 页 / 共 4 页
字号:

<p><font color="#0000FF"><b>目录</b></font></p>
<p>每个子系统都给其它子系统提供了接口,你甚至不需要深入每个子系统的细节,仅仅搞清楚子系统的接口就可以进行内核级的程序开发了。<br>
</p>
<p><font size="4" color="#0000FF"><b><a href="#内核地址空间的布局">内核地址空间的布局</a></b></font></p>
<p><font size="4" color="#0000FF"><b><a href="#初始化和固定映射">初始化和固定映射&nbsp;           
&nbsp;</a></b></font></p> 
<p><font size="4" color="#0000FF"><b><a href="#Boot mem">Boot mem</a></b></font></p>          
<p><font size="4" color="#0000FF"><b><a href="#高端内存">高端内存</a></b></font></p> 
<p><font size="4" color="#0000FF"><b><a href="#VM 和 vmalloc">VM 和 vmalloc</a></b></font></p>           
<p><font size="4" color="#0000FF"><b><a href="#物理内存管理">物理内存管理</a></b></font></p> 
<p><font size="4" color="#0000FF"><b><a href="#slab 管理">slab 管理</a></b></font></p>                     
<p><font size="4" color="#0000FF"><b>page cache</b></font></p>                     
<p><font size="4" color="#0000FF"><b>swap cache 和 swap file</b></font></p>           
<p><font size="4" color="#0000FF"><b><a href="#虚存管理(vma)">虚存管理(vma)</a></b></font></p> 
<p><font size="4" color="#0000FF"><b><a href="#swap out">swap out</a></b></font></p>             
<p><font size="4" color="#0000FF"><b><a href="#swap in">swap in</a></b></font></p>            
<p><font size="4" color="#0000FF"><b><a href="#mm fault handle">mm fault handle</a></b></font></p>            
<p><b><font size="4" color="#0000FF"><a href="#mmap">mmap</a></font></b></p>           
      <p class="post"> 
      <br> 
      <span class="post">我的理解是这样:<br> 
      1.可以分成两个部分讨论:<br> 
      <br> 
      内核空间的内存管理<br> 
      用户空间的内存管理<br> 
      <br> 
      2<br> 
      对于用户空间管理,正如你说的,核心是映射,映射操作由cpu自动完成的,但是如何映射是linux定的。<br> 
      <br> 
      正如数学中定义的,关于一个映射有3个要素;<br> 
      <pre>
定义域

  |

  | 映射规则

  V

值域

</pre> 
      <br> 
      因此要完成一个映射的定义,需要<br> 
      <br> 
      在用户空间分配一个定义域(vm_area_struct的分配等操作);<br> 
      在“物理地址”上分配一个值域(内核空间的分配----页面级分配器);<br> 
      定义映射(页表操作);<br> 
      <br> 
      3<br> 
      对于其它操作,也可以从这个3要素来考虑<br> 
      <br> 
      比如交换:<br> 
      <br> 
      就是把一部分值域“搬迁”到“外设”中,映射原象一端固定住,“象”一端也跟着移到“外设”中<br> 
      <br> 
      交换中的缺页中断<br> 
      不过是把部分“值域”再搬回到内存中来</span> 
<p> </p>           
<hr> 
<p> </p> 
<p><b><font size="6" color="#0000FF"><a name="内核地址空间的布局">内核地址空间的布局</a></font></b></p> 
<p><b><font size="6" color="#0000FF">&nbsp;</font></b> 我们计算一下,              
如果4G的空间都有映射那么页表占去了多少空间:一个页表4K(一个pte代表4K),              
pgd 中有1024 项(每一项代表4M空间 ),那么就需要 4K*(1024+1) = 4M+4k              
的空间.</p> 
<p>&nbsp; 内核的pgd 是 <font color="#800080"><b>swapper_pg_dir</b></font>,静态分配,              
系统初始化时把前768项空出来.              
也就是只初始化了3G以上的空间,              
编译时内核的虚拟地址从3G开始.这样内核通过这个页目录寻址.初始化时映射的这一部分空间称为<font color="#FF0000"><b>预映射</b>.</font>预映射把所有物理内存映射到内核,              
同时p--v              
转换非常简单,使得内核无须维护自己的虚拟空间,并且能够方便的存取用户空间.</p> 
<p><font color="#FF0000">&nbsp; </font>众所周知的,<b><font color="#800080">__pa</font></b>  
宏基于这样的预映射.内核拥有独立的pgd,              
也就是说内核的虚拟空间是独立于其他程序的.这样以来和其他进程完全没有联系.那么我们所说的用户在低3G,内核在最高1G,为所有用户共享,              
又是怎么回事呢? 其实很简单, 进程页表前768项指向进程的用户空间,如果进程要访问内核空间,如系统调用,则进程的页目录中768项后的项指向swapper_pg_dir的768项后的项。然后通过swapper_pg_dir来访问内核空间。一旦用户陷入内核,就使用内核的<font color="#800080"><b>swapper_pg_dir(不是直接使用而是保持用户pgd              
768后面的和 swapper_pg_dir  
一致,共享内核页表{因为到内核不切换pgd?}看看</b></font><font color="#0000FF"><a href="#do_page_fault">do_page_fault</a>  
^_^</font><font color="#0000FF"> 的相关处理</font><b><font color="#800080">)</font></b>进行寻址!</p> 
<p>&nbsp; linux 把他的1G线性空间分成了几个部分:</p>             
<p>1) Linux将整个4G线性地址空间分为用户空间和内核空间两部分,而内核地址空间又被划分为&quot;物理内存区&quot;,              
&quot;虚拟内存分配区&quot;, &quot;高端页面映射区&quot;,&quot;专用页面映射区&quot;,              
&quot;系统保留映射区&quot;几个区域.<br> 
<br> 
2) 在标准配置下, <font color="#800080">物理区</font>最大长度为896M,系统的物理内存被顺序映射在物理区中,在支持扩展页长(PSE)和全局页面(PGE)的机器上,物理区使用4M页面并作为全局页面来处理(呵呵,没有白白计算).              
当系统物理内存大于896M时,超过物理区的那部分内存<br> 
称为<font color="#800080">高端内存</font>,低端内存和高端内存用<b><font color="#800080">highmem_start_page</font></b>变量来定界,<b><font color="#FF0000">内核</font></b>在存取高端内存时必须将它们映射到&quot;高端页面映射区&quot;.<br> 
<br> 
3) Linux保留内核空间最顶部<font color="#800080">128K</font>区域作为<font color="#800080">保留区</font>,紧接保留区以下的一段区域为<font color="#800080">专用页面映射区</font>,它的总尺寸和每一页的用途由<font color="#800080">fixed_address</font>枚举结构在编绎时预定义,用__fix_to_virt(index)可获取专用区内预定义页面的逻辑地址.在专用页面区内为每个CPU预定义了一张高端内存映射页,用于在中断处理中高端页面的映射操作.<br>             
<br> 
4) 距离内核空间顶部32M, 长度为4M的一段区域为<font color="#800080">高端内存映射区</font>,它正好占用1个页帧表所表示的物理内存总量,              
它可以缓冲1024个高端页面的映射.在物理区和高端映射区之间为<font color="#800080">虚存内存分配区</font>,              
用于vmalloc()函数,它的<font color="#800080">前部与物理区有8M隔离带</font>,              
后部与高端映射区有8K(2.4为4k?)的隔离带.<br> 
<br> 
5) 当系统物理内存超过4G时,必须使用CPU的扩展分页(PAE)模式所提供的64位页目录项才能存取到4G以上的物理内.在PAE模式下,              
线性地址到物理地址的转换使用3级页表,第1级页目录由线性地址的最高2位索引,              
每一目录项对应1G的寻址空间,第2级页目录项以9位索引,              
每一目录项对应2M的寻址空间, 第3级页目录项以9位索引,每一目录项对应4K的页帧.              
除了页目录项所描述的物理地址扩展为36位外,64位和32位页目录项结构没有什么区别.              
在PAE模式下,包含PSE位的中级页目录项所对应的页面从4M减少为2M.<br> 
</p> 
<p><br> 
内核的1G线性空间(灰色代表已经建立映射,只有物理区为完全映射)<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p> 
<div align="left"> 
  <table border="1" width="678" height="49"> 
    <tr> 
      <td width="83" height="23">&nbsp; 物理区</td>             
      <td width="27" height="24" bgcolor="#000000"><font color="#FFFF00">8M隔离</font></td> 
      <td width="222" height="1" colspan="5">&nbsp;&nbsp;&nbsp;&nbsp; vmalloc              
        区</td> 
      <td width="25" height="48" bgcolor="#000000"><font color="#FFFF00">8K隔离</font></td> 
      <td width="118" height="1" colspan="3">4M的高端映射区</td> 
      <td width="100" height="1" colspan="2">固定映射区</td> 
      <td width="57" height="48">&nbsp;128K 
        <p>保留区</td> 
    </tr> 
    <tr> 
      <td width="83" height="70" bgcolor="#C0C0C0"> </td> 
      <td width="27" height="69" bgcolor="#000000"> </td> 
      <td width="32" height="70"></td> 
      <td width="14" height="70" bgcolor="#C0C0C0"> </td> 
      <td width="56" height="70"></td> 
      <td width="13" height="70" bgcolor="#C0C0C0"> </td> 
      <td width="83" height="70"></td> 
      <td width="25" height="64" bgcolor="#000000"> </td> 
      <td width="40" height="69"></td> 
      <td width="25" height="69" bgcolor="#C0C0C0"> </td> 
      <td width="41" height="69"></td> 
      <td width="52" height="60"></td> 
      <td width="42" height="60" bgcolor="#C0C0C0"> </td> 
      <td width="57" height="64" bgcolor="#FF0000"> </td> 
    </tr> 
  </table> 
</div> 
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  
</font></b>|&lt;------------- 32M----------------&gt;|<br>            
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;             
<b><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;           
V</font></b></p> 
<div align="center"> 
  <center> 
  <table border="1" width="478" height="55"> 
    <tr> 
      <td width="178" height="55" bgcolor="#808000"><font color="#0000FF">和物理区对应的物理内存</font></td> 
      <td width="128" height="55" bgcolor="#800000"><font color="#00FF00"><b>被映射到高端映射区的物理内存</b></font></td> 
      <td width="150" height="55" bgcolor="#800000"><font color="#00FFFF">其他高端物理内存</font></td> 
    </tr> 
  </table> 
  </center> 
</div> 
<p>下面从代码中寻找一下根据(上面的分析好像不是2.4.0, ^_^):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>             
<p>下面的代码摘自 <font color="#FF0000"><b>include/asm-386/pgtable.h</b></font></p>             
<p>/* Just any arbitrary offset to the start of the vmalloc VM area: the<br>  
 * current 8MB value just means that there will be a 8MB "hole" after the<br>  
 * physical memory until the kernel virtual memory starts.  That means that<br>  
 * any out-of-bounds memory accesses will hopefully be caught.<br>  
 * <font color="#FF0000"> The vmalloc() routines leaves a hole of 4kB between each vmalloced</font><br>  
 * <font color="#FF0000"> area for the same reason.</font> ;)<br>  
 */<br> 
#define VMALLOC_OFFSET	(8*1024*1024)<br>  
#define <font color="#FF0000"> VMALLOC_START</font>	(((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) &amp; \<br>  
						~(VMALLOC_OFFSET-1))<br> 
#define VMALLOC_VMADDR(x) ((unsigned long)(x))<br>  
#define <font color="#FF0000"> VMALLOC_END</font> (FIXADDR_START)</p> 
<p>可以看出物理区 和 VM 区中间的那个空洞.而vmalloc区结束和固定映射区开始也应该是4k的空洞啊!</p>             
<p> </p>
<p><b><font color="#FF0000">fixmap.h</font></b></p>
<p><font color="#800080"><b>fixed_addresses&nbsp; </b></font>看看这个结构就知道,高端内存映射区属于固定内存区的一种,并且每个cup一个.</p>
<pre>enum <b><font color="#800080">fixed_addresses</font></b> {
#ifdef CONFIG_X86_LOCAL_APIC
	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
#endif
#ifdef CONFIG_X86_IO_APIC
	FIX_IO_APIC_BASE_0,
	FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
#endif
#ifdef CONFIG_X86_VISWS_APIC
	FIX_CO_CPU,	/* Cobalt timer */
	FIX_CO_APIC,	/* Cobalt APIC Redirection Table */ 
	FIX_LI_PCIA,	/* Lithium PCI Bridge A */
	FIX_LI_PCIB,	/* Lithium PCI Bridge B */
#endif
#ifdef CONFIG_HIGHMEM
	<font color="#FF0000">FIX_KMAP_BEGIN</font>,	/* reserved pte's for temporary kernel mappings */
	<font color="#FF0000">FIX_KMAP_END</font> = <font color="#FF0000">FIX_KMAP_BEGIN</font>+(<font color="#FF0000">KM_TYPE_NR</font>*<font color="#FF0000">NR_CPUS</font>)-1,
#endif
	__end_of_fixed_addresses
};</pre>
<p>这个文件的以下定义也非常有意义:</p>
<p>/*<br>
 * used by vmalloc.c.<br>            
 *<br> 
 * Leave one empty page between vmalloc'ed areas and<br>            
 * the start of the fixmap, and leave one page empty<br>            
 * at the top of mem..<br>            
 */<br> 
#define <font color="#FF0000"> FIXADDR_TOP</font>	(0xffffe000UL)<br>            
#define <font color="#FF0000"> FIXADDR_SIZE</font>	(__end_of_fixed_addresses &lt;&lt; PAGE_SHIFT)<br>            
#define <font color="#FF0000"> FIXADDR_START</font>	(FIXADDR_TOP - FIXADDR_SIZE)<br>            
<br> 
顶端好像不是留了128 k 而是4k.</p>            
<p> </p>
<hr>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -