ION是Android引入的一种避免内存碎片化的内存管理方式,用于分配连续或不连续内存。为了满足各种场景下的内存分配要求,ION引入了内存heap的概念.一个内存heap定义和实现了内存分配的方式或者用途.
1.内存heap
1.1 heap类型
enum ion_heap_type {
ION_HEAP_TYPE_SYSTEM,//分配的物理页面不保证是连续的.类似于vmalloc的实现
ION_HEAP_TYPE_SYSTEM_CONTIG,//分配连续的物理页面,类似与kmalloc的实现
ION_HEAP_TYPE_CARVEOUT,//从保留内存分配连续物理页面,且把内存添加到memory pool管理
ION_HEAP_TYPE_CHUNK,//从保留内存分配chunk size个不连续的内存,且把内存添加到memory pool管理
ION_HEAP_TYPE_DMA,//从伙伴系统分配连续物理内存,一般通过CMA内存来实现
ION_HEAP_TYPE_CUSTOM, /* //平台商自定义heap类型,可以自定义内存分配方式.
* must be last so device specific heaps always
* are at the end of this enum
*/
ION_NUM_HEAPS = 16,
};
1.2 heap结构体和实现函数
struct ion_heap {/*只保留重要变量 */
struct plist_node node;//系统所有的heap都要链接到ion_device
struct ion_device *dev;//目前系统有且仅有一个ion_device
enum ion_heap_type type;//heap 类型
struct ion_heap_ops *ops;//heap需要实现的内存操作函数集,如果alloc/free/map_user/map_kernel等等
struct shrinker shrinker;//注册到内存回收的回调函数,因为heap一般会有memory pool.
};
比如系统heap的内存操作集函数
static struct ion_heap_ops system_heap_ops = {
.allocate = ion_system_heap_allocate,//负责分配内存,通过alloc_pages实现
.free = ion_system_heap_free,//释放内存,会做memory pool缓存
.map_dma = ion_system_heap_map_dma,//DMA操作,一般范围SG地址
.unmap_dma = ion_system_heap_unmap_dma,//umap
.map_kernel = ion_heap_map_kernel,//把物理内存映射到内核,通过vmap实现(dma heap除外)
.unmap_kernel = ion_heap_unmap_kernel,
.map_user = ion_heap_map_user,//把物理内存映射到用户空间,通过remap_pfn_range函数实现(dma heap除外)
.shrink = ion_system_heap_shrink,
};
1.3 注册heap到ion core
ion系统,可以分为两个层次,ion core和ion heap
ion core负责实现通用API接口,而ion heap负责各种heap内存分配.
创建ion device : ion_device_create
创建heap : ion_heap_create
添加heap到ion : ion_device_add_heap
2. ion常用API和数据结构
驱动会注册misc /dev/ion导出给用户空间使用. 以ioctl command来交互
定义了6种 ioctl 接口,可以与用户应用程序交互。
ION_IOC_ALLOC: 分配内存ion_alloc,最终会调用具体heap的alloc函数
ION_IOC_FREE:ion_free 释放内存
ION_IOC_MAP/ION_IOC_SHARE: ion_share_dma_buf_fd创建文件描述符来实现mmap和共享内存
ION_IOC_IMPORT: ion_import_dma_buf通过fd来获取对应的buffer
ION_IOC_CUSTOM: 调用用户自定义的ioctl
这里需要关注ION_IOC_MAP/ION_IOC_SHARE,会创建虚拟的file结点,设置dma的mmap操作集,把ion与文件系统关联起来,.这样用户才能对内存进行mmap操作
2.1 常用数据结构
ion_device,系统有且只有一个,通过ion_device_create创建
struct ion_device {
struct miscdevice dev;// misc device 结构体/dev/ion
struct rb_root buffers;//系统所有ion_buffer红黑树
struct plist_head heaps;//系统所有heap的优先级链表
struct rb_root clients;//系统所有client的红黑树链表
/*在/sys/kernel/debug/ion目录生成调试接口 */
struct dentry *debug_root;
struct dentry *heaps_debug_root;
struct dentry *clients_debug_root;
};
ion_client表示一个客户端,也就是内存的申请者,通过ion_client_create创建
struct ion_client {
struct rb_node node;//链接到ion_device红黑树
struct ion_device *dev;//ion_device
struct rb_root handles;// client分配的内存红黑树,一个handles表示一个内存引用.
struct task_struct *task;//分配进程
struct dentry *debug_root;//调试接口
};
ion_buffer表示一次内存分配,在ion_alloc中分配.
struct ion_buffer {
struct kref ref;//ion_buffer本身引用
struct rb_node node;//链接到ion_client
struct ion_device *dev;//ion deivice
struct ion_heap *heap;// 指向分配的heap
void *vaddr;//内核虚拟地址
struct sg_table *sg_table;//sg散列表,
struct page **pages;//具体的page
/* used to track orphaned buffers */
int handle_count;//buffer应用计数
char task_comm[TASK_COMM_LEN];//进程名
};
ion_handle可以理解为ion_buffer的一个引用
struct ion_handle {
struct kref ref;//ion handle计数
struct ion_client *client;//指向分配者
struct ion_buffer *buffer;//ion buffer
struct rb_node node;//链接到ion_client红黑树
};
3. 使用案例
3.1用户空间
void main()
{
int *p;
struct ion_fd_data fd_data;
struct ion_allocation_data ionAllocData;
ionAllocData.len=0x1000;
ionAllocData.align = 0;
ionAllocData.flags = ION_HEAP_TYPE_SYSTEM;
int fd=open("/dev/ion",O_RDWR);
ioctl(fd,ION_IOC_ALLOC, &ionAllocData);
fd_data.handle = ionAllocData.handle;
ioctl(fd,ION_IOC_SHARE,&fd_data);
p=mmap(0,0x1000,PROT_READ|PROT_WRITE,MAP_SHARED,fd_data.fd,0);
p[0]=99;
perror("test");
printf("hello all %d\n",p[0]);
}
3.2内核空间
extern struct ion_device *g_idev;
void allocfromion()
{
int *buf;
struct ion_handle *data;
client = ion_client_create(g_idev, -1, "kernel");
data = ion_alloc(client,0x1000,0,ION_HEAP_SYSTEM_MASK);
buf = ion_map_kernel(client,data);
}
4. 调试接口
/sys/kernel/debug/ion/buffer//系统所有buffer
/sys/kernel/debug/ion/client//打印client使用内存情况
/sys/kernel/debug/ion/event//alloc/free/mmap等事件
/sys/kernel/debug/ion/heap//各种堆的使用情况