linux内存管理初学

虚拟内存模型

Linux 内核本身并不运行在虚拟空间中,其使用的是物理寻址模式。

    物理内存被分割为界面,一个内存页面的大小由PAGE_SIZE宏决定。

虚拟地址空间的方式使程序员可以将巨大的结构用于连续的地址,而不必考虑物理内存上的限制。

线性地址到物理地址

线性地址需要由处理器或者一个单独的MMU转换为物理地址,转换方式如下:

 

解析的方式为:

1.用线性地址中的第一个位段为下标可以在页面目录中找的一个表项,这个表项指向某个中间目录。

2.用线性地址中的第二个位段为下标可以在该中间目录中找到一个表项,该表项指向某个页面表。

3.用线性地址中的第三个位段为下标可以在该页面表中找到一个表项,该表项指向物理内存中的某个物理页面。

4.用线性地址中的第四个位段为偏移量,将次偏移量与该物理页面的基地址相加便得到相应的物理地址。

注 : TLB中存的是页面目录基地址。

 

而内核空间的线性地址解析成物理地址的过程相对简单,因为系统本身要为自己维护一张页表是一件很恶心的事情,所以内核空间的地址和物理地址是简单的直接映射,0xc0000000就是两者的偏移量。

也就是说:对于系统空间,给定一个虚地址x,其物理地址是x中减去PAGE_OFFSET;相应的,给定一个物理地址x,其虚地址是x+PAGE_OFFSET

当然,不能全部用来做简单映射,因为如果内存有4G,那么如果直接全部做简单映射,那么内核只能访问0-1G的内存了,所以内核中实际是前896M做直接映射,剩下的用来做vmalloc申请区,永久内存映射区,固定映射区等。如下图:

 

 

 

几个创建进程函数

Fork子进程只是复制父进程的资源,两进程内存空间独立,运行时并行。为了降低运行时的开销,对资源采用写时复制(也就是fork并不直接拷贝资源,只是当发生写入的时候才完成拷贝)。

Vfork共享地址空间,创建后进程父进程阻塞直到子进程结束。

Clone有参数,可以有选择的将数据复制给子进程,剩下的通过指针共享。

几个申请内存的函数的区别

1. kmallocvmalloc分配内核空间的内存,malloc分配用户空间的内存。

2. kmalloc物理连续,vmalloc虚拟地址连续。

3. kmalloc能分配的空间大小有限,vmallocmalloc能分配的较大。

4. 内存在被DMA时需要物理连续。

5. Kmalloc更快

6. Kmalloc使用slab机制,返回地址之后就已经对应实际内存了。

缺页中断

如果MMU处理器不能访问一个页面,它将产生一个缺页中断。Linux缺页异常程序必须能区分由编程引起的以及由引用属于地址空间还未分配物理页框的页引起的异常,如果合法则分配新的页框。

每个进程都有自己的页表。

页面管理

请求换页

    为了节省内存,操作系统只会加载那些正在被执行程序使用的虚拟页面。比如,某个数据库程序可能要对某个数据库进行查询操作,此时并不是数据库的所有内容都要加载到内存中去,而只加载那些要用的部分。这种仅将要访问的界面载入的技术叫请求换页

 

当进程试图访问不在内存中的虚拟地址时,将触发一个缺页中断

 

如果出错的地址是无效的,比如进行了一个随机的写操作,则操作系统终止此进程,此进程的出错不会影响其他进程。

 

如果出错的地址是有效的,但是它访问的页面不在内存中。则操作系统必须将此界面从磁盘映像中读出来。访盘时间比较长,进程必须等待一段时间直到页面被取出来。取过来的页面放在一个空闲的物理页框之中,同时此进程的页表中将添加对应此虚拟页面框号的入口。然后进程从出错的地方从新开始运行。

 

交换

如果进程需要把一个虚拟页面调入物理内存而正好系统没有空闲的物理页面,操作系统必须丢弃系统中某些页面来为之腾出空间。

 

如果那些从物理内存中丢弃出来的界面来自于磁盘上的可执行文件或者数据文件,并且没有修改过则不需要保存那些界面。当进程再次需要此页面时,直接从可执行文件或者数据文件中读出即可。

 

但是如果页面被修改过,则系统必须将其保存以备再次访问。这种界面叫做dirty界面。当从内存中移出来的时候,他们必须保存在叫做交换文件的特殊文件中。相对于cpu和内存的速度,访问交换文件的速度很慢,所以操作系统必须衡量好将那些dirty页交换或将其保留在内存中做出一个选择。

 

如果丢弃页面的算法选择的不够好,则可能不断地出现页面被写入又被从磁盘中读回的情况使效率变低。Linux使用最近最少使用(LRU)页面衰老算法来公平的选择将要从系统中抛弃的页面。这种算法为每个页面设置一个年龄,它随页面访问次数而变化。页面被访问的次数越多则越年轻,相反则衰老。

 

Linux高速缓冲

缓冲区高速缓冲(buffer cache

     缓冲区高速缓冲包含了由块设备使用的数据缓冲区。这些缓冲区包含了从设备中读取的数据块或写入设备的数据块。如果数据能够在缓冲区高速缓冲中找到,则系统没有必要在物理块设备上进行实际的读操作。

页面高速缓冲(page cache

页面高速缓冲是页面I/O操作访问数据所使用的磁盘高速缓存。我们在文件系统会看到,read()write()mmap()系统调用对常规文件的访问都是通过页面高速缓存来完成的。

    缓冲区高速缓存和页面高速缓存的区别:缓冲区高速缓存是块设备的cache,页面高速缓冲是用来做文件系统的cache,也就是它直接记忆我们打开的文件(例如使用两次man命令,可以明显感觉第二次更快)。

交换高速缓冲(swap cache

就是交换空间在内存中的缓存。当写入交换空间的文件并没有被再次修改,那么下次再丢弃他的时候就不需要再次写入交换空间,这个就是通过swap cache来做的。

 

 

注意:

使用top命令会发现有buffercache的概念:

Buffer:简单的说是要被写入磁盘的,磁盘和主存的速度不一,所以需要缓冲区做一个中间层,写入数据的话先写入缓冲区,这样的话写入的进程没有必要陷入等待。

Cache(非CPU和主存件的cache):简单的说就是从磁盘读入的,存储在cache里以备后面再次使用。经常被用在磁盘I/O请求上,如一个文件被访问,则其将被放入cache中,以备以后再有进程访问。

 

Cachebuffer都是需要占用内存的。

 

原文:

A buffer is something that has yet to be "written" to disk. A cache is something that has been "read" from the disk and stored for later use.





posted @ 2015-11-22 21:49  DChipNau  阅读(292)  评论(0编辑  收藏  举报