内存是Linux内核所管理的最重要的资源之一.
内存管理子系统是操作系统中最重要的部分之一.
物理地址:现在CPU外部地址总线上的寻址.
逻辑地址:汇编程序使用的地址.
虚拟地址:(线性地址),在32位CPU架构下,可以表示4G地址空间.
段式管理:
物理地址 = 段地址 * 16 + 偏移地址
或
PA = 段寄存器的值 * 16 + 逻辑地址(偏移量)
页式管理:线性地址被分为固定长度的:页(4KB).
Linux内存管理:有限度的使用了分段机制.
在Linux中提到的逻辑地址和线性地址(虚拟地址)指的就是同一地址.完全利用了分页机制.
虚拟内存:
Linux操作系统采用虚拟内存的管理技术,使得每个进程都有独立的进程地址空间,大小为3G.
用户程序可使用比实际物理内存更大的地址空间.
Linux的虚拟内存空间有4G,分为用户空间和内核空间.
用户空间:0~~0xbfffffff
内核空间:3G~~4G
每当进程切换,用户空间就会跟着变化,而内核空间不变,固定.
查看进程线性地址:cat
内核内存分配:#include <linux/slab.h>
void *kmalloc (size_t size , int flags)
size:分配的内存大小.
flags:分配的标志 , 控制kmalloc的行为.
(常用)GFP_KERNEL:进程上下文的分配,可能睡眠.
按页分配:(不会产生碎片)
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以上的部分称之为高端内存.
内核空间分布:
直接内存映射区:线性地址 = 3G + 物理地址
动态内存映射区:由内核函数vmalloc 分配
永久内存映射去:访问方法:1.alloc_page (_ _GFP_HIGHMEM)
(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);
list_add_tail (struct list_head *new , struct list_head *head);
删除节点:
list_del (struct list_head *entry);
提取数据结构:
list_entry (ptr , type , member);
功能:已知数据结构的节点指针ptr,找出数据结构.
ptr:结点中的指向指针域的指针.
type:结点的类型. 例:struct student
member:结点中指针域的名称.
返回:指向该结点的头地址.
遍历:
list_for_each (struct list_head *pos , struct list_head *head);
pos:获取已经遍历的指针域,不断变化.
head:传入链表头.
例子:
Linux内核定时器:
unsigned long
延迟执行:
内核定时器被组织成双向链表.
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);
(超时后,系统会自动将定时器删除)