A. linux系统为什么给内核分配1G不是500M为什么不是2:2分配
所有进程都必须占用一定数量的内存,这些内存用来存放从磁盘载入的程序代码,或存放来自用户输入的数据等。内存可以提前静态分配和统一回收,也可以按需动态分配和回收。
对于普通进程对应的内存空间包含5种不同的数据区:
代码段
数据段
BSS段
堆:动态分配的内存段,大小不固定,可动态扩张(malloc等函数分配内存),或动态缩减(free等函数释放);
栈:存放临时创建的局部变量;
其中物理地址空间中除了896M(ZONE_DMA + ZONE_NORMAL)的区域是绝对的物理连续,其他内存都不是物理内存连续。在虚拟内核地址空间中的安全保护区域的指针都是非法的,用于保证指针非法越界类的操作,vm_struct是连续的虚拟内核空间,对应的物理页面可以不连续,地址范围(3G + 896M + 8M) ~ 4G;另外在虚拟用户空间中 vm_area_struct同样也是一块连续的虚拟进程空间,地址空间范围0~3G。
B. Linux内核空间内存动态申请
在Linux内核空间中申请内存涉及的函数主要包括kmalloc () 、_get_free _pages ()和vmalloc(等。kmalloc()和_get_free pages ()(及其类似函数)申请的内存位于DMA和常规区域的映射区,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系。而vmalloc()在虚拟内存空间给出一块连续的内存区,实质上,这片连续的虚拟内存在物理内存中并不一定连续,而vmalloc ()申请的虚拟内存和物理内存之间也没有简单的换算关系。
1.kmalloc ( )
给kmalloc() 的第一个参数是要分配的块的大小;第二个参数为分配标志,用于控制kmalloc ()的行为。最常用的分配标志是GFP_KERNEL,其含义是在内核空间的进程中申请内存。kmalloc ()的底层依赖于_get_free pages ()来实现,分配标志的前缀GFP正好是这个底层函数的缩写。使用GFP_KERNEL标志申请内存时,若暂时不能满足,则进程会睡眠等待页,即会引起阻塞,因此不能在中断上下文或持有自旋锁的时候使用GFP_KERNE申请内存。由于在中断处理函数、tasklet和内核定时器等非进程上下文中不能阻塞,所以此时驱动应当使用GFP_ATOMIC标志来申请内存。当使用GFP_ATOMIC标志申请内存时,若不存在空闲页,则不等待,直接返回。
其他的申请标志还包括GFP_USER(用来为用户空间页分配内存,可能阻塞)、GFP_HIGHUSER(类似GFP_USER,但是它从高端内存分配)、GFP_DMA(从DMA区域分配内存)、GFP_NOIO(不允许任何IO初始化)、GFP_NOFS(不允许进行任何文件系统调用)、__GFP_ HIGHMEM(指示分配的内存可以位于高端内存)、__(GFP COLD(请求一个较长时间不访问的页)、_GFP_NOWARN(当一个分配无法满足时,阻止内核发出警告)、_GFP_HIGH(高优先级请求,允许获得被内核保留给紧急状况使用的最后的内存页)、GFP_REPEAT(分配失败,则尽力重复尝试)、_GFP_NOFAIL(标志只许申请成功,不推荐)和__GFPNORETRY(若申请不到,则立即放弃)等。
使用kmalloc()申请的内存应使用kfree()释放,这个函数的用法和用户空间的free()类似。
2._get_free_pages ()
_get_free pages ()系列函数/宏本质上是Linux内核最底层用于获取空闲内存的方法,因为底层的buddy算法以2n页为单位管理空闲内存,所以最底层的内存申请总是以2n页为单位的。
get_free _pages ()系列函数/宏包括get_zeroed _page () 、_get_free_page ()和get_free pages () 。
__get_free_pages(unsigned int flags, unsigned int order) 该函数可分配多个页并返回分配内存的首地址,分配的页数为2order,分配的页也不清零。order允许的最大值是10(即1024页)或者11(即2048页),这取决于具体的硬件平台。