美文网首页
[读书笔记]分配内存(第八章)

[读书笔记]分配内存(第八章)

作者: c枫_撸码的日子 | 来源:发表于2018-10-27 10:31 被阅读0次

综述

本章主要学习设备驱动程序中,常用的分配内存的方法

kmalloc函数的内幕

1.函数原型

#include  <linux/slab.h>
void *kmalloc(size_t size,ini flags);
参数一:分配内存的大小
参数二:分配标志

2.size参数

内核分配内存的方法:创建一系列的内存对象池,
每个池中的内存块大小是固定一致的。
内核只能分配一些预定义的、固定大小的字节数组。
kmalloc能处理的最小内存块是32或者64,取决于cpu平台。

3.参数二:flags标志

驱动开发最常用的2个标志位:
1.GFP_KERNEL
表示内存分配(最终总是调用get_free_pages来实现实际的分配,
这既是GFP_前缀的由来)是由运行在内核空间的进程执行的,
可能会引起休眠
2.GFP_ATOMIC
用于在进程上下文之外(如中断处理例程、tasklet以及内核定时器调用)的代码中分配内存,
不会休眠
------------------------------------------------------------------------
其他标志
1.GFP_USER
用于为用户空间分配内存,可能会休眠
2.GFP_HIGHUSER
类似于GFP_USER,如果存在高端内存的话,就从那里分配
3.GFP_NOIO
4.GFP_NOFS
这2个标志类似GFP_KERNEL,但是有一些限制,GFP_NOFS的分配不允许执行任何文件系统的调用。
而GFP_NOIO禁止任何I/O的初始化。

------------以上标志可以和下面标志“或”起来用------------

_ _GFP_DMA
 请求分配发送在可进行DMA的内存区段中。

_ _GFP_HIGHMEM
表明要分配的内存可位于高端内存

_ _GFP_COLD
通常,内存分配会试图返回“缓存热”页面,即可在处理器缓存中找到的页面,
该标准请求尚未使用的"冷"页面。

_ _GFP_NOWARN
很少使用,避免在内核无法满足分配请求时产生警告

__GFP_HIGH
高优先级的请求,允许为紧急状态下而消耗由内存保存的最后一些页面

_ _GFP_REPEAT
内存分配失败时请求再次分配

_ _GFP_NOFAIT
不推荐使用,告诉分配器始终不返回失败

_ _GFP_NOREPEAT
如果内存请求失败,立即返回

4.内存区段

Linux内核把内存分为三个区段:
1.可用于DMA的内存
2.常规内存
3.高端内存(kmalloc不能分配高端内存)

后备高速缓存(lookaside cache)

1.slab分配器-用于创建高速缓存的对象

#include <linux/slab.h>
kmem_cache_t *kmem_cache_create(const char *name,size_t size,
                              size_t offset,
                              unsigned long flags,
                              void (*constructor)(void *,kmen_cache_t *,
                                                         unsigned long flags),
                              void (*destructor)(void *,kmem_cache_t*,
                                                         unsigned long flags));
参数:
const char *name:高速缓存对象的名称
size_t size:分配内存的大小
size_t offset:页面中第一个对象的偏移量,用于对齐,通常为0
unsigned long flags:分配标志
1.SLAB_NO_REAP 2.SLAB_HWCACHE_ALIGN 3.SLAB_CACHE_DMA

constructor和destructor参数可选的函数,
前者用于初始化新分配的对象,后者用于清除对象,一般都为NULL即可。

2.分配内存

void *kmem_cache_allpc(kmem_cache_t *cache,int flags);
参数一:cache是先前创建的高速缓存对象
参数二:flags和kmalloc的相同

3.释放内存对象

void kmem_cache_free(kmem_cache_t *cache,const void *obj);

4.释放内存

int kmem_cache_destory(kmem_cache_t *cache);

内存池

1.创建内存池的对象类型

#include <linux/mempool/h>
mempool_t *mempool_create(int min_nr
                          mempool_alloc_t *alloc_ fn
                          mempool_free_t *free_fn
                          void *pool_data);

cache = kmem_cache_create(...);
pool = mempool_create(8,mempool_alloc_slab,mempool_free_slab,cache);

2.分配和释放对象

void *mempool_alloc(mempool_t *pool,ini gfp_masl);
void mempool_free(void *element,mempool_t *pool);

3.调整mempool的大小

int mempool_resize(mempool_t *pool,init new_min_nr,int gfp_mask);

4.释放内存

void mempool_destroy(mempool_t *pool);

get_free_page

如果需要分配大块的内存,就应该使用面向页的分配技术。
1.分配内存

get_zeroed_page(unsigned int flags)
返回指向新页面的指针并且将页面清零
_ _get_free_page(unsigned int flags)
返回指向新页面的指针 但是页面不清零
_ _get_free_pages(unsigned int flags,unsigned int order)
分配若干、物理连续的页面,并返回指向该内存区域的第一个字节的指针,不清零页面
第一个参数和kmalloc一样,第二个参数是要申请或者释放的页面数,以2为底数(log2N)

2.释放内存

void free_page(unsigned long addr)
void free_pages(unsigned long addr,unsigned long order)

alloc_pages接口

1.struct page 用来描述单个内存页的数据结构
2.Linux页分配器的核心代码

struct page *alloc_pages_node(int nid,unsigned int flags,unsigned int order);
参数:
nid 是NUMA节点的ID号,表示要在其中分配内存。
flags和kmalloc的一样
order表示要分配的内存大小

变种
struct page *alloc_pages(unsigned int flags,unsigned int order);
struct page *alloc_page(unsigned int flags);

3.释放内存

void _ _free_page(struct page *p);
void _ _free_pages(struct page *p,unsigned int order);
void free_hot_page(struct page *p);
void free_cold_page(struct page *p);

vmalloc及辅助函数

1.vmaloc是内存分配函数,分配虚拟地址空间的连续区域(物理上可能不是连续的),它是linux内存分配机制的基础,但是不推荐使用此函数分配内存,只是了解即可。

#include <linux/vmalloc.h>
void * vmalloc(unsigned long size);
void * vfree(void *addr);

#include <asm/io.h>
void *ioremap(unsigned long offset,unsigned long size);
void iounmap(void * addr);
这些函数分配或者释放连续的虚拟地址空间。
ioremap通过虚拟地址访问物理内存,而vmalloc分配空闲页面。
使用ioremap映射的区域用iounmap释放。

per-CPU变量

#include <linux/percpu.h>
DEFINE_PER_CPU(type,name);
DECLARE_PER_CPU(type,name);
定义和声明per-CPU变量的宏
per-cpu(variable,int cpu_id);
get_cpu_var(variable);
put_cpu_var(vatiable);
用于访问静态声明的per-CPU的宏

void *alloc_percpu(type);
void * __alloc_percpu(size_t size,size_t align)
void free_percpu(void *variable);
执行per-CPU变量的运行时分配和释放的函数

int get_cpu();
void put_cpu();
per_cpu_ptr(void *variable,int cpu_id);
get_cpu获得对当前处理器的引用(避免抢占以及切换到其他处理器)并返回处理器的ID号;
而put_cpu返回该引用。为了访问动态分配的per-CPU变量,应使用per_cpi_ptr,
并且传递要访问的变量版本的CPU ID号。
对某个动态的per-CPU变量的当前CPU版本的操作,应该包含在对get_cpu和put_cpu的调用中间。

在系统引导时获得专用缓存区

#include <linux/bootmem.h>
void *alloc_bootmem(unsigned long size);
void *alloc_bootmem_low(unsigned long size);
void *alloc_bootmem_pages(unsigned long size);
void *alloc_bootmem_low_pages(unsigned long size);
void free_bootmem(unsigned long addr,unsigned long size);
在系统引导期间执行内核分配和 释放的函数。
这些函数只能在直接链接到内核的驱动程序中使用。

相关文章

  • ULK3 based on kenerl 2.6.11 读书笔

    第八章 内存管理 本章通过三部分内容描述内核给自己动态分配内存: ...

  • [读书笔记]分配内存(第八章)

    综述 本章主要学习设备驱动程序中,常用的分配内存的方法 kmalloc函数的内幕 1.函数原型 2.size参数 ...

  • 《C语言》malloc函数使用

    动态分配、静态分配 静态分配:计算机随机自动分配内存,周期结束后自动释放内存动态分配:手动分配内存,手动释放内存 ...

  • (二)C语言之动态内存分配

    (二)C语言之动态内存分配 一、静态内存分配 定义是指定分配的内存长度就是静态内存分配,是在栈内存中分配 二、C语...

  • Java内存区域与内存溢出异常

      《深入理解Java虚拟机》第2章读书笔记与实验记录。 1、对象创建内存分配方式 指针碰撞: Java堆内存绝对...

  • javascript内存管理

    内存声明周期 分配你所需要的内存 使用分配的内存(读写) 不再需要时释放内存 内存分配 javascript在声明...

  • docker 的资源分配

    内存分配 -m 或者--memory :分配内存--memory-swap:分配临时内存docker run -i...

  • Java中四种引用

    Java内存管理包括内存分配和内存回收。 内存分配:程序员通过new对象,JVM会自动为该对象分配内存。 内存回收...

  • Java编程语言:java中四种引用!欢迎补充

    Java内存管理包括内存分配和内存回收。 内存分配:程序员通过new对象,JVM会自动为该对象分配内存。 内存回收...

  • 回顾JVM内存分配

    回顾JVM内存分配回顾JVM内存分配

网友评论

      本文标题:[读书笔记]分配内存(第八章)

      本文链接:https://www.haomeiwen.com/subject/ctwxtqtx.html