zoukankan      html  css  js  c++  java
  • 读书笔记Linux内核设计与实现part 3

    Chapter 12 内存管理》

     

    MMU:内存管理单元,管理内存,地址转换,通常以页为单位管理。

    从虚存角度看,页是最小单位。

     

    struct page {
      unsigned long     flag;             //页是否脏,是否被锁定在内存
      atomic_t          _count;           //页引用计数
      atomic_t          _mapcount;       //
      unsigned long     private;
      struct address_space *mapping;
      pdoff_t           index;
      struct list_head     lru;
      void              *virtual;
    }

     

     

    一个页的用途:由页缓存使用(mapping域指向与这个页关联的address_space)、作为私有数据(由private指向)、作为进程页表中的映射。

    virtual域是页的虚拟地址(页在虚存中的地址)。

    struct page是与物理页相关。

    页的拥有者:用户进程空间、动态分配的内核数据、静态代码段、页高速缓存 等。

     

    内存分区(ZONE):

    某些硬件特性导致内存页面不能被一视同仁。

    Linux使用了四种区:ZONE_DMA、ZONE_DMA32、ZONE_NORMAL、ZONE_HIGHMEM。

    区的使用与体系结构相关,例如,x86下,ISA设备不能使用32位的地址空间,只能使用0~16M的空间,所以ZONE_DMA包含在0~16M这个范围内。

    struct zone;

     

    获得页:

    //获取2^order个连续的物理页。

    struct page* alloc_page(gfp_t gfp_mask, unsigned int order);

    //将struct page转为对应的逻辑地址

    void* page_address(struct page* page);

    unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);

    struct page* alloc_page(gfp_t gfp_mask);

    unsigned long __get_free_page(gfp_t gfp_mask);

    unsigned long get_zeroed_page(gfp_t gfp_mask);

    分配内存可能失败,失败时可能需要回到以前的状态,所以一开始就申请内存是个不错的想法。

     

    释放页:

    void __free_pages(struct page* page, unsigned int order);

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

    void free_page(unsigned long addr);

    释放页时只能释放属于自己的页,这个需要函数调用者保证。

     

    kmalloc:

    按字节分配,物理上连续。

    void* kmalloc(size_t sizem gfp_t flag);

    分配器标志:行为修饰符、区修饰符、类型。

    void kfree(const void *ptr)

     

    vmalloc:类似于kmalloc,但是vmalloc分配的内存虚拟地址是连续的,物理地址可能不连续。它分配非连续的物理页,然后通过‘修正’页表,将内存映射到逻辑地址空间的连续区域中。大多数情况下,只有硬件设备需要得到物理地址连续的内存。

    vmalloc性能差于kmalloc(页表转换),且可能导致TLB抖动,所以vmalloc在不得已时才使用(例如,大块内存)。

     

    slab:

    一种对象对应于一种高速缓存,每一个高速缓存又被划分成slab,一个slab是由一个或连续几个物理页组成的。slab中存放数据结构。slab可能是满的,部分满的,空的。

    例如struct inode由inode_cachep分配。

     

     

     

    高速缓存永kmem_cache结构体来表示。这个结构体有三个链表 slab_full, slab_partial, slab_empty。

     

    struct slab {
      struct list_head list;    //满(/部分/空)链表
      unsigned long coloroff;   //着色偏移?
      void *s_mem;                //第一个对象
      unsigned int inuse;        //已分配的对象个数
      kmem_bufctl_t free;        //第一个空闲对象
    }

     

    相关接口:

     

    构造高速缓存:

    struct kmem_cache *kmem_cache_create(const char* name,

                                           size_t size,   //每个元素的大小

                                           size_t align,

                                           unsigned long  flags,

                                           void (*ctor)(void*));

    ctor是构造器,在高速缓存分配新页的时候调用。事实上,Linux不使用,设为NULL即可。

     

    销毁高速缓存:

    int kmem_cache_destroy(struct kmem_cache *cachep);

     

    从高速缓存中分配/释放一个对象:

    void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);

    void *kmem_cache_free(struct kmem_cache *cachep, void *objp);

     

     

    内核栈可以是一页或者两页,历史上,中断处理程序和进程共享一个内核栈,当内核栈只有一页时,中断使用自己的栈(中断栈)。

     

    高端内存的映射:

    将一个struct page(对应一个物理页)映射到虚存(返回虚拟地址):

    void* kmap(struct page *pg) //可能睡眠

    解除映射:

    void* kunmap(struct page *pg)

    临时映射(不睡眠)和解除映射

    void* kmap_atomic(struct page* pg, enum km_type type)

    void* kunmap_atomic(struct page* pg, enum km_type type)

     

     

    CPU数据:

    使用每CPU数据的原因:

    1. 减少了数据锁定
    2. 减少缓存失效

     

    接口:

    编译时定义每个CPU变量 

    DEFINE_PER_CPU(type, name); //为每个处理器都定义了一个类型为type变量名为name的变量。

    DECLARE_PER_CPU(type, name);

    get_cpu_var(name)++; //加1,同时禁止抢占

    put_cpu_var(name);   //重新允许抢占

     

    运行时每CPU数据:

    void *alloc_percpu(tpye); //一个宏

    viud *__alloc_percpu(size_t size, size_t align);

    void free_percpu(const void*);

     

    get_cpu_var(ptr); //返回一个void类型的指针,指向ptr

    put_cpu_var(ptr); //重新激活内核抢占

     

     

  • 相关阅读:
    MySQL中查询表及索引大小的方法
    转:一套大而全的系统架构体系与具体落地方案
    [转]1年时间业务量疯长40倍,谈人人车的平台架构演进之路
    [转]如何实现“持续集成”?闲鱼把研发效率翻了个翻
    微服务介绍
    Python2.X和Python3.X的w7同时安装使用
    黑客与画家阅读体会
    Open Source 开发工具集
    volatile和不加volatile的区别
    VMware改变硬盘空间大小的方法
  • 原文地址:https://www.cnblogs.com/apprentice89/p/2796813.html
Copyright © 2011-2022 走看看