Linux内核学习之三——内存管理

一、Linux内存管理(子系统)
地址类型:
1)物理地址:物理地址是指出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果。
2)线性地址(虚拟地址)32位 ox00000000---0xffffffff
3)逻辑地址:程序代码经过编译后在汇编程序中使用的地址。
通过段式管理单元得到线性地址,再通过页式管理得到物理地址

什么是段式管理
逻辑地址=段内偏移量
1》对于16位CPU
PA = 段寄存器的值*16 + 逻辑地址
0=======2^16-1  (2^16*0)
0=======2^16-1  (2^16*1)
0=======2^16-1  (2^16X2)
0=======2^16-1  (2^16X4)
0=======2^16-1  (2^16X15)

2》对于32位的X86cpu,段基地址寄存器内存放的不再是基地址,而是内存区域的地址,通过该地址找到基地址。
3》实模式 保护模式


什么是页式管理
2^10*2^10*2^12共覆盖2^32 ---两页
Linux内存管理时,巧妙的绕过了段式管理。
段基地址都是为0

二、Linux进程地址空间
每个进程都有独立的进程地址空间3G
用户看到和接触到得都是虚拟地址
还有1G是内核空间
两空间互相访问:系统调用和中断
每当进程切换,用户空间跟着变化cr3寄存器的值变化
/cat/proc/<pid>/maps查看  线性地址相同 物理地址不同

fork() execve malloc只是分配到线性地址 也就是虚拟地址 用的时候才会分配物理地址
有4G的范围 可以交错使用 不能同时使用
比如:分配了100字节的内存 不写数据不分配物理内存
内核中分配内存:kmalloc,有两个参数:大小和标志
GFP_KERNEL:如果没有内存分配 就会导致睡眠 16-896M之间分配
GFP_ATOMIC:不会睡眠
__GFP_DMA:DMA传输的内存在16M以下的页帧
__GFP_HIGHMEM:896以上

按页分配(分配比较大时)
get_zeroed_page 清零的
__get_free_page

当程序使用完后 一定要free
free_page  free_pages

内存使用:
用户空间:
 malloc fork excute mmap:虚拟内存
内核:
 kmalloc:物理内存
 Vmalloc:虚拟内存

slab 内存管理机制?

三、Linux内核地址空间(1G)
内核地址空间不会随着进程改变
物理内存896M-1G是高端内存,
1》直接映射区:线性地址=3G+物理地址--kmalloc 最大896M
2》Vmalloc区 动态内存映射区 最小120M
3》永久内存映射区 高端内存 KMAP区 固定4M
4》固定映射区 如ACPI_BASE 地址映射寄存器 不要修改,固定4M


四、Linux内核链表
单链表 双链表 循环链表

include/linux/list.h中 一套精彩的链表实现
可以将其移植到应用程序中
内核中,更多的时候是双向链表

五、Linux内核定时器

Linux内核定时器 驱动时会用到
通过时钟中断计算时间间隔
HZ宏可以配置
例如 一秒钟1000个中断
每次中断(1/1000秒),全局变量jiffies加1
jiffies unsigned long
利用jiffies做一个延迟

内核定时器控制让某个函数在某时间执行
这个定时器不是循环的 只执行一次

删除定时器 超时之前取消 若已经超时 无需del

 

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/list.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Xie");
MODULE_DESCRIPTION("List Module");
MODULE_ALIAS("List module");

struct student
{
    char name[100];
    int num;
    struct list_head list;
};

struct student *pstudent;
struct student *tmp_student;
struct list_head student_list;
struct list_head *pos;

int mylist_init()
{
    int i = 0;
   
    INIT_LIST_HEAD(&student_list);
   
    pstudent = kmalloc(sizeof(struct student)*5,GFP_KERNEL);
    memset(pstudent,0,sizeof(struct student)*5);
   
    for(i=0;i<5;i++)
    {
      sprintf(pstudent[i].name,"Student%d",i+1);
        pstudent[i].num = i+1;
        list_add( &(pstudent[i].list), &student_list);
    }
    //#define list_for_each(pos, head) \
    //for (pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next)
   
    list_for_each(pos,&student_list)
    {
        //#define container_of(ptr, type, member) ({const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})
        tmp_student = list_entry(pos,struct student,list);
        printk("<0>student %d name: %s\n",tmp_student->num,tmp_student->name);
    }
   
    return 0;
}


void mylist_exit()
{  
    int i ;
    /* 实验:将for换成list_for_each来遍历删除结点,观察要发生的现象,并考虑解决办法 */
    for(i=0;i<5;i++)
    {
        list_del(&(pstudent[i].list));    
    }
   
    kfree(pstudent);
}

module_init(mylist_init);
module_exit(mylist_exit);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值