linux内存管理

本文深入探讨了Linux内存管理的核心机制,包括页面管理、初始化、请求与释放页面、Buddy系统算法、slab算法、非连续内存区管理以及内存分配方式等关键概念。
1. 内存使用,
   分为两部分,一部分是永久归内核使用的部分,另一部分是用户使用的动态内存.
   页面管理与内存区管理/不连续内存区管理

2. 页面管理
   linux使用4KB的页面大小,

3.内存的初始化:
   页面的初始化由free_area_init()函数进行,并计算页面的数量及大小,并给mem_map分配足够的空间,给内核用于记录页面的指针.
   此时,这些页面就可以给其它的进程使用,

4. 请求与释放页面
   __get_free_pages()获取连续的页面
   __get_dma_pages(),获取适合DMA的页面
   __get_free_page().获取一个页面

   __free_page(); 释放页面
   
5. Buddy系统算法:
   原因:外碎片问题,频繁的请求与释放不同大小的一组连续页面,会导致碎片的问题,避免的方式有两种:
   1. 利用分页单元,把一组非连续的空闲页面框架映射到连续的线性地址上.
   2. 开发一种适当的技术,来记录现存的空闲页面,以尽量避免分隔
   linux使用的是第二种方法:
   概念: 把所有的页面分组为10块链表,每个链表使用包含大小为1/2/4/8/16/32/64/128/256/512连续大小的页面.

6. slab算法:
   原因:内碎片问题.分配的页大小过于大,造成浪费

7. 非连续内存区管理:
   把一块存放slab结构的内存区映射到一组连续的物理页是最好的选择,这样子会充分利用高速缓存并获得较低的平均访问时间。但是,这主要是使用非常频繁的内核数据结构,如task_struct,inode.
   若对内存区的请求不是很频繁,那么通过连续的线性地址,而不是物理地址来访问非连续的物理页框架就会有意义的多。
   这种模式主要是避免了外碎片,不足是会打乱内核页表,此外,非连续的内存区的大小必须是4K的倍数,
   linux使用该方法的地方有:为活动的交换分区分配数据结构,为模块分配空间,或者为某IO驱动分配缓冲区。此外,非连续内存区还提供另一种高端的内存页面框架,


   vmalloc()给函数分配一个非连续内存区:过程概述:
   1. 将参数设为4096的整数倍,然后,vmalloc()调用get_vm_area()创建一个新的描述符,并返回分配给这个内存的线性地址,描述符的flag字段为VM_ALLOC,然后,非连续页框被映射到一个线性地址区间
   然后,会调用kmalloc()请求一组连续的页框,然后,调用memset()将所有的指针设为NULL,接着重复调用alloc_page()函数.至到完成.

   释放非连续内存:
   vfree().
   
8. 内核与进程的内存分配方式:
   内核函数,可以直接获得动态内存.只是通过几个函数调用,get_free_page(),获得页框,kmem_cache_alloc()或kmalloc()为slab分配对象,使用vmalloc()获取非连续的内存区.
   若这些函数可以满足,则返回的是线性地址,这个线性地址就是内存动态分配的起始地址.

   当用户态的进程分配内存时,完全不一样了.
   1.不会很紧迫的分配内存,内核会尽量迟的给用户态进程分配内存.
   2.内核会随时捕获用户态进程的所有寻址错误.

   进程的地址空间是由允许的全部线性地址组成,每个进程看到的线性地址是不同的.一个进程看到的地址与另一个无任何关系.
   与创建/删除线性区相关的系统调用.

   brk()        改变进程堆的大小
   execve()        装入一个新的可执行文件,从而改变进程的地址空间
   exit()        结束当前进程并撤销它的地址空间
   fork()        创建一个新的进程,并为它创建新的地址空间
   mmap()        为一个文件创建一个内存映射,从而扩大进程的地址空间
   munmap()        撤消对文件的内存映射,从而缩小进程的地址空间
   shmat()        创建一个共享地址空间
   shmdt()        撤消一个共享地址空间

   进程拥有的所有线性区是通过一个链表连接在一起的.而每两个出现在链表中的线性区,可能是分开的.内核频繁执行的一个操作就是查找线性地址所在的线性区.
   因为,线性区使用的链表很少,所以,一般这些操作所花费的时间与线性区个数成比例.
   不过,当一些大的应用程序,可能会有成百上千的线性区,此时,使用的链表管理算法是:AVL树.
   AVL树: 优点:可以大量的增加访问速度,不足:它的处理函数复杂.在元素数目小时,效率很低.所以,linux会在32的线性区时,使用AVL算法

   堆的管理:
   每个linux都有一个特殊的线性区,叫堆(heap),用于进程的动态内存的请求,内存描述符的start_brk()与brk()域分别限定了这个区的开始地址和结束地址.
   malloc(),  calloc(),  free(),  brk()
   其中,brk()是系统函数,其它的都是使用它的.
   

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值