0
点赞
收藏
分享

微信扫一扫

Linux内核的内存管理

前端王祖蓝 2022-03-22 阅读 46
linux

1.基本概念

	1) linux内核管理内存时以页(page)为单位
		通常一个物理内存页的大小为4KB
		内核会为每个物理内存页建立一个数据结构
			include/linux/mm_types.h
			struct page {
				//保存该内存被引用的次数 为0 代表空闲页
				atomic_t _refcount; 
			};
			
	2) linux内核在管理内存时,并不是一视同仁
		高端内存: 物理内存超过896M(大小可调)的空间
				动态映射的策略
				使用时进行映射,使用完毕后马上解除映射

在这里插入图片描述

				动态内存映射区
				永久内存映射区
				固定内存映射区
		
		低端内存: 介于0896M的内存称为低端内存
				映射关系是固定的 
				虚拟地址= 0xc0000000 + 物理偏移

在这里插入图片描述

2.内核中动态申请内存的方法

	2.1 按页申请
		方式一: 
			alloc_pages(gfp_t gfp_mask, unsigned int order);
				order,要申请 2^order 个物理内存页
			static inline void *page_address(const struct page *page);
				将page指定的物理内存进行映射
				返回映射后的起始虚拟地址
		方式二:
			__get_free_pages(gfp_t gfp_mask, unsigned int order);
				order,要申请 2^order 个物理内存页
		方式三:
			unsigned long __get_free_page(unsigned int flags);//申请一个物理内存页
			unsigned long get_zeroed_page(gfp_t gfp_mask);//申请一个物理内存页,并清0
		
			free_pages(unsigned long addr, unsigned int order);
			
	2.2 按字节申请
		方式一:
			kmalloc/kfree
			void *kmalloc(size_t size, gfp_t flags);
				size,要申请的字节数
				flags, 
					常用的取值: GFP_KERNEL,申请内存过程中 可能发生阻塞
										  不能用于中断上下文
							  GFP_ATOMIC,申请不成功 直接返回错误 不会阻塞
							  			可以用于中断上下文
				分配得到的物理内存是连续的 (执行效率高)
				
			kfree(void *p) 
				p, kmalloc返回的虚拟地址
				
			
		方式二:
			vmalloc/vfree
			void *vmalloc(unsigned long size);
				size, 要申请的字节数
				得到的虚拟地址是连续的
				但是其对应的物理地址可能不连续
			void vfree(const void *addr);//一定不要在中断上下文中使用
				
	2.3 映射之后的相互转换
			使用的前提是已经建立了映射
			//虚拟地址转物理地址
			phys_addr_t virt_to_phys(const volatile void *x);
			//物理地址转虚拟地址
			void *phys_to_virt(phys_addr_t x);
	#include <linux/init.h>
	#include <linux/module.h>
	#include <linux/vmalloc.h>
	#include <linux/slab.h>

	MODULE_LICENSE("GPL");
	unsigned long pages_addr = 0;
	void * kmalloc_addr = 0;
	void * vmalloc_addr = 0;

	int __init kernelspace_init(void)
	{
	  int err = 0;
	  /*申请8个空闲物理内存页*/
	  pages_addr = __get_free_pages (GFP_KERNEL, 3); 
	  if (!pages_addr)
	  {
	    err = -ENOMEM;
	    goto failure_get_free_pages;
	  }
	  printk ("pages virt addr = %p phy addr = %p", pages_addr, virt_to_phys(pages_addr));

	  kmalloc_addr = kmalloc(100, GFP_KERNEL);
	  if (!kmalloc_addr)
	  {
    	err = -ENOMEM;
	    //return err;//不能在这里直接返回,会发生内存泄漏
	    goto failure_kmalloc;
	  }
	  printk ("kmalloc vir addr = %p, phy addr = %p\n", kmalloc_addr, virt_to_phy(kmalloc_addr));

	  vmalloc_addr = vmalloc(10*1024);
	  if (!vmalloc_addr)
	  {
	    err = -ENOMEM;
    	goto failure_vmalloc;
	  }
	  return 0;

	failure_vmalloc:
	  kfree(kmalloc_addr);
	failure_kmalloc:
	  free_pages (pages_addr, 3); 
	failure_get_free_pages:
	  return err;
	}

	void __exit kernelspace_exit(void)
	{
	  vfree(vmalloc_addr);
	  kfree(kmalloc_addr);
	  free_pages(pages_addr,3);
	}

	module_init(kernelspace_init);
	module_exit(kernelspace_exit);
举报

相关推荐

0 条评论