Linux内存管理

来源:互联网 发布:js导出csv 编辑:程序博客网 时间:2024/06/06 19:33


内存是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 , intflags)

size:分配的内存大小.

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

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

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

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

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

 

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

get_zeroed_page (unsigned intflags);

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

 

_ _get_free_page (unsigned intflags);

同上,但是不清零.

 

_ _get_free_pages (unsigned int flags , unsigned intorder);

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

 

释放内存页面:

void free_page (unsigned longaddr);

void free_pages (unsigned long addr , unsigned intorder);

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

 

高端内存:物理内存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 , structlist_head *head); (插入head前面)

 

删除节点:

list_del (structlist_head *entry);

 

提取数据结构:

list_entry (ptr ,type , member);

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

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

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

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

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

 

遍历:

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

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

head:传入链表头.

例子:

         struct list_head *entry;

         struct list_headmy_list;   //链表头

         list_for_each (entry ,&my_list)

          {

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

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

          }

 

Linux内核定时器:

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

延迟执行:

                 unsigned long j = jiffies + delay * HZ;

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

 

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

struct timer_list{

struct list_headentry;  //内核使用.

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

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

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

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
原创粉丝点击