Linux内存管理


内存是Linux内核所管理的最重要的资源之一.

内存管理子系统是操作系统中最重要的部分之一.

 

物理地址:现在CPU外部地址总线上的寻址.

                   物理内存的地址信号,是地址变换的最终结果.

逻辑地址:汇编程序使用的地址.

虚拟地址:(线性地址),在32位CPU架构下,可以表示4G地址空间.

Linux内存管理

段式管理:

                 16位的CPU内部拥有20位的地址线,寻址范围是2^20 (1M)的内存空间.

                 1.逻辑的起始地址(段地址),必须是16的倍数.即:最后低4位为零.

                 2.逻辑段的最大容量是64K. (因为第四位全位零.)

物理地址 = 段地址 * 16 + 偏移地址

PA = 段寄存器的值 * 16 + 逻辑地址(偏移量)

 

页式管理:线性地址被分为固定长度的:页(4KB).

Linux内存管理:有限度的使用了分段机制.

                            所有的段的基地址均为0.

                            逻辑地址到线性地址映射保持不变.

在Linux中提到的逻辑地址和线性地址(虚拟地址)指的就是同一地址.完全利用了分页机制.

 

虚拟内存:

Linux操作系统采用虚拟内存的管理技术,使得每个进程都有独立的进程地址空间,大小为3G.

用户程序可使用比实际物理内存更大的地址空间.

 

Linux的虚拟内存空间有4G,分为用户空间和内核空间.

用户空间:0~~0xbfffffff  (0~3G)

内核空间:3G~~4G  (系统调用方式访问)

每当进程切换,用户空间就会跟着变化,而内核空间不变,固定.

查看进程线性地址:cat  /porc/<pid>/maps     (<pid>:进程号)

 

内核内存分配:#include <linux/slab.h>

void *kmalloc (size_t size , int flags)

size:分配的内存大小.

flags:分配的标志 , 控制kmalloc的行为.

           GFP_ATOMIC:用来在进程上下文之外的代码(包括中断处理)中分配内存,从不睡眠.

(常用)GFP_KERNEL:进程上下文的分配,可能睡眠.   (16M~~896M)

          _GFP_DMA:分配能够DMA的内存区.    (物理地址16M以下的页帧)

         _GFP_HIGHMEM:分配内存位于高端内存.   (896M以上)

 

按页分配:(不会产生碎片)

get_zeroed_page (unsigned int flags);

返回指向新页面的指针,并将页面清零.

 

_ _get_free_page (unsigned int flags);

同上,但是不清零.

 

_ _get_free_pages (unsigned int flags , unsigned int order);

分配若干个连续的页面,返回指向该内存区的指针,但不清零.

 

释放内存页面:

void free_page (unsigned long addr);

void free_pages (unsigned long addr , unsigned int order);

如果释放的和先前分配的数目不等的页面数,会导致系统错误.

 

高端内存:物理内存896M以上的部分称之为高端内存.

 

内核空间分布:

Linux内存管理

直接内存映射区:线性地址 = 3G + 物理地址

动态内存映射区:由内核函数vmalloc 分配

永久内存映射去:访问方法:1.alloc_page (_ _GFP_HIGHMEM)

(KMAP区)                                2.kmap函数.

固定映射区:寄存器之类地址.

 

Linux内核链表:#include <linux/list.h>

链表数据结构定义:

struct list_head {

struct list_head *next , *pre;

};

(通常是双向循环链表)

 

链表操作:

初始化链表头.

INIT_LIST_HEAD (list_head *head);

 

插入节点:

list_add (struct list_head *new , struct list_head *head);  (插入head后面)

list_add_tail (struct list_head *new , struct list_head *head);  (插入head前面)

 

删除节点:

list_del (struct list_head *entry);

 

提取数据结构:

list_entry (ptr , type , member);

功能:已知数据结构的节点指针ptr,找出数据结构.

ptr:结点中的指向指针域的指针.

type:结点的类型. 例:struct student   填写:struct student

member:结点中指针域的名称.

返回:指向该结点的头地址.

 

遍历:

list_for_each (struct list_head *pos , struct list_head *head);

pos:获取已经遍历的指针域,不断变化.

head:传入链表头.

例子:

          struct list_head *entry;

          struct list_head my_list;    //链表头

          list_for_each (entry , &my_list)

          {

               info = list_entry (entry , struct my_list_info , list);

               if (info -> data == test) break;

           }

 

Linux内核定时器:

unsigned long  jiffies;    //全局变量.每当时钟中断发生时就加1;

延迟执行:

                  unsigned long j = jiffies + delay * HZ;

                  while (jiffies < j)   { }      //延迟了delay 秒.

 

内核定时器被组织成双向链表.

struct timer_list {

struct list_head entry;   //内核使用.

unsigned long expires;   //设置超时所用的时间.

void (*function)(unsigned long );   //超时处理调用的函数.

unsigned long data;    //超时处理函数的参数.

struct tvec_base *base;   //内核使用.

};

 

操作定时器的函数如下:

初始化定时器队列结构

void init_timer (struct timer_list *timer);

 

启动定时器

void add_timer (struct timer_list *timer);

 

超时前删除定时器

int del_timer (struct timer_list *timer);

(超时后,系统会自动将定时器删除)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值