1. 内存管理简介: 不同架构下的编址方式可能是不一样的:
ARM中寄存器和内存统一编址X86中内存按地址编址,寄存器用端口号编址
对于包含 MMU 的处理器而言,Linux 系统提供了复杂的存储管理系统,使得进程所能访问的内存达到 4GB。
在 Linux 系统中,进程的 4GB 内存空间被分为两个部分:
<img id="aimg_TyPe7" class="zoom" file="http://img.blog.csdn.net/20160909180110164" lazyloadthumb="1" border="0" alt="" />
一般情况,用户进程通常情况下只能访问用户空间的虚拟地址,不能访问内核空间虚拟地址。
每个进程的用户空间都是完全独立、互不相干的,用户进程各自有不同的页表。
内核空间是由内核负责映射,它并不会跟着进程改变,是固定的。
在 3~4GB 之间的内核空间中,从低地址到高地址依次为:
物理内存映射区—隔离带—vmalloc虚拟内存分配器 — 隔离带—高端内存映射区—专用页面映射区—保留区
2. 内存存取2.1 用户空间内存的分配:void *malloc(size_t nbytes); //返回指向nbytes个字节的指针void *calloc(size_t cnt, size_t nbytes); //内容清0void *realloc(void *ptr,size_t size); //改变当前分配的空间,参数size 是重新分配后的大小,一般是要变大void free(void *ptr); //释放动态分配的内存空间1234
1234
2.2 内核空间内存的分配:(1) kmalloc: – 分配小空间(32,128k)函数原型:
static void *kmalloc(size_t size, gfp_t flags)1
1
参数: size,分配空间的大小,范围 (32, 128k),单位是字节 flags, #define GFP_ATOMIC (__GFP_HIGH) //非阻塞分配 #define GFP_KERNEL (__GFP_WAIT | __GPF_IO | __GFP_FS) //阻塞分配释放函数是:kfree
(2) __get_free_page: –最小单位是 4k,最大能分配8M函数原型:
unsigned long __get_free_page(int gfp_mask);unsigned long __get_free_page(int gfp_mask, unsigned long order);12
12
注意点:
返回页首地址,不清 0 内容,分配的页数是2的order次,则分配的大小是还要乘4k,order最大是11,则最大能分配的空间是2k*4k = 8M
参数: gfp_mask, #define GFP_ATOMIC (__GFP_HIGH) //非阻塞分配 #define GFP_KERNEL (__GFP_WAIT | __GPF_IO | __GFP_FS) //阻塞分配释放函数:
free_pagefree_pages12
12
前两个分配的空间都是物理地址和虚拟地址连续的
(3) vmalloc: –可分配8M以上的空间,获得的地址是平台相关的,不能在中断时分配函数原型:
void *vmalloc(unsigned long size)1
1
特点是:
物理地址不一定连续,虚拟地址连续
释放函数:
void vfree(void * addr); 1
1
(4) slab: – 分配特定结构的内存块用合适的方法使得在对象前后两次被使用时分配在同一块内存或同一类内存空间且保留了基本的数据结构
创建 slab 缓存:
struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void*, struct kmem_cache *, unsigned long), void (*dtor)(void*, struct kmem_cache *, unsigned long)); 1234
1234
参数:
name,名字size,每个数据结构的大小align,flags,如何进行分配的位掩码: SLAB_NO_REAP,即使内存紧缺也不自动收缩这块缓存 SLAB_HWCACHE_ALIGN,每个数据对象被对齐到一个缓存行 SLAB_CACHE_DMA,要求数据对象在DMA内存区分配ctor,dtor,分配 slab 缓存: – 在 kmem_cache_create()创建的 slab 后备缓冲中分配一块并返回首地址指针
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);1
1
释放 slab 缓存: – 释放由 kmem_cache_alloc()分配的缓存
void kmem_cache_free(struct kmem_cache *cachep, void *objp); 1
1
收回 slab 缓存:
int kmem_cache_destroy(struct kmem_cache *cachep); 1
1
使用模板:
/*创建 slab 缓存*/ static kmem_cache_t *xxx_cachep; xxx_cachep = kmem_cache_create(&quot;xxx&quot;, sizeof(struct xxx), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); /*分配 slab 缓存*/ struct xxx *ctx; ctx = kmem_cache_alloc(xxx_cachep, GFP_KERNEL); .../* 使用 slab 缓存 */ /*释放 slab 缓存*/ kmem_cache_free(xxx_cachep, ctx); kmem_cache_destroy(xxx_cachep); 1234567891011
1234567891011
在linux系统下可以通过 /proc/slabinfo 节点来获知当前 slab 的分配和使用情况。
(5) 内存池创建内存池:
mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t *free_fn, void *pool_data); 12
12
参数:
min_nr,需要预分配对象的数目
alloc_fn 和 free_fn,指向内存池机制提供的标准对象分配和回收函数的指针
函数原型分别是
typedef void *(mempool_alloc_t)(int gfp_mask, void *pool_data);
typedef void (mempool_free_t)(void *element, void *pool_data);
pool_data 是分配和回收函数用到的指针,gfp_mask是分配标记。只有当_ _GFP_WAIT 标记被指定时,分配函数才会休眠。 |