济南营销网站制作,图片wordpress主题,国家企业公示信息系统全国,网站等保需要几年一做内存堆管理应用示例
这是一个内存堆的应用示例#xff0c;这个程序会创建一个动态的线程#xff0c;这个线程会动态申请内存并释放#xff0c;每次申请更大的内存#xff0c;当申请不到的时候就结束。
#include rtthread.h#define THREAD_PRIORITY 25
#defi…内存堆管理应用示例
这是一个内存堆的应用示例这个程序会创建一个动态的线程这个线程会动态申请内存并释放每次申请更大的内存当申请不到的时候就结束。
#include rtthread.h#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5/* 线程入口 */
void thread1_entry(void *parameter)
{int i;char *ptr RT_NULL; /* 内存块的指针 */for (i 0; ; i){/* 每次分配 (1 i) 大小字节数的内存空间 */ptr rt_malloc(1 i);/* 如果分配成功 */if (ptr ! RT_NULL){rt_kprintf(get memory :%d byte\n, (1 i));/* 释放内存块 */rt_free(ptr);rt_kprintf(free memory :%d byte\n, (1 i));ptr RT_NULL;}else{rt_kprintf(try to get %d byte memory failed!\n, (1 i));return;}}
}int dynmem_sample(void)
{rt_thread_t tid RT_NULL;/* 创建线程 1 */tid rt_thread_create(thread1,thread1_entry, RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY,THREAD_TIMESLICE);if (tid ! RT_NULL)rt_thread_startup(tid);return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(dynmem_sample, dynmem sample);
内存池
内存堆管理器可以分配任意大小的内存块非常灵活和方便。 但其也存在明显的缺点
分配效率不高在每次分配时都要在空闲内存块查找。容易产生内存碎片。
为了提高内存分配的效率并且避免内存碎片RT-Thread提供了另外一种内存管理方法内存池Memory Pool。
内存池是一种内存分配方式用于分配大量大小相同的小内存块它可以极大加快内存分配与释放的速度且能尽量避免内存碎片化。 此外RT-Thread的内存池支持线程挂起功能当内存池中无空闲内存块时申请线程会被挂起直到内存池中有新的可用内存块再将挂起的申请线程唤醒。
内存池的线程挂起功能非常适合需要通过内存资源进行同步的场景例如播放音乐时播放器线程会对音乐文件进行解码然后发送到声卡驱动从而驱动硬件播放音乐。 当播放器线程需要解码数据时就会向内存池请求内存块如果内存块已经用完线程将被挂起否则它将获得内存块以放置解码的数据。播放器线程把包含解码数据的内存块写入到声卡抽象设备中线程会立刻返回继续解码出更多的数据。当声卡设备写入完成后将调用播放器线程设置的回调函数释放写入的内存块如果在此之前播放器线程因为把内存池里的内存块都用完而被挂起的话那么这时它将被将唤醒并继续进行解码。
内存池控制块
内存池控制块是操作系统用于管理内存池的一个数据结构它会存放内存池的一些信息例如内存块数据区域开始地址内存块大小和内存块列表等也包含内存块与内存块之间连接用的链表结构因内存块不可用而挂起的线程等待事件集合等。
struct rt_mempool
{struct rt_object parent;void *start_address; //内存池数据区域开始地址rt_size_t size; //内存池数据区域大小rt_size_t block_size; //内存块大小rt_uint8_t *block_list; //内存块列表/* 内存池数据区域中能够容纳的最大内存块数 */rt_size_t block_total_count;/* 内存池中空闲的内存块数 */rt_size_t block_free_count;/* 因为内存块不可用而挂起的线程列表 */rt_list_t suspend_thread;/* 因为内存块不可用而挂起的线程数 */rt_size_t suspend_thread_count;
};typedef struct rt_mempool* rt_mp_t;内存块分配机制
内存池在创建时先向系统申请一大块内存然后分成同样大小的多个小内存块小内存块直接通过链表连接起来此链表也称为空闲链表。 每次分配的时候从空闲链表中取出链头上第一个内存块提供给申请者。 物理内存中允许存在多个大小不同的内存池每一个内存池又由多个空闲内存块组成内核用它们来进行内存管理。 当一个内存池对象被创建时内存池对象就被分配给了一个内存池控制块内存池控制块的参数包括内存池名内存缓冲区内存块大小块数以及一个线程等待队列。 内核负责给内存池分配内存池控制块它同时也接收用户线程的分配内存块申请。 内存池一旦初始化完成内部的内存块大小将不能再做调整。
suspend_thread形成了一个申请线程等待列表即当内存池中无可用内存块并且申请线程允许等待时申请线程将挂在suspend_thread链表上。
内存池的管理方式
内存池控制块是一个结构体其中含有内存池相关的重要参数。
创建和删除内存池
创建内存池操作将会创建一个内存池对象并从堆上分配一个内存池。
rt_mp_t rt_mp_create(const char* name,rt_size_t block_count, rt_size_t block_size);使用该函数接口可以创建一个与需求的内存块大小、数目相匹配的内存池前提当然是在系统资源允许的情况下最主要的内存堆内存资源才能创建成功。
创建内存池时需要给内存池指定一个名称。 然后内核从系统中申请一个内存池对象然后从内存堆中分配一块由块数目和块大小计算得来的内存缓冲区接着初始化内存池对象并将申请成功的内存缓冲区组织成可用于分配的空闲块链表。
删除内存池将删除内存池对象并释放申请的内存。
rt_err_t rt_mp_delete(rt_mp_t mp);删除内存池时会首先唤醒等待在该内存池对象上的所有线程返回-RT_ERROR然后再释放已从内存堆上分配的内存池数据存放区域然后删除内存池对象。
内存池应用示例
这是一个静态内存池应用例程创建一个静态的内存池对象2个动态线程1个线程试图从内存池中获得内存块另一个线程释放内存块。
#include rtthread.hstatic rt_uint8_t *ptr[50];
static rt_uint8_t mempool[4096];
static struct rt_mempool mp;#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5/* 指向线程控制块的指针 */
static rt_thread_t tid1 RT_NULL;
static rt_thread_t tid2 RT_NULL;/* 线程 1 入口 */
static void thread1_mp_alloc(void *parameter)
{int i;for (i 0 ; i 50 ; i){if (ptr[i] RT_NULL){/* 试图申请内存块 50 次当申请不到内存块时线程 1 挂起转至线程 2 运行 */ptr[i] rt_mp_alloc(mp, RT_WAITING_FOREVER);if (ptr[i] ! RT_NULL)rt_kprintf(allocate No.%d\n, i);}}
}/* 线程 2 入口线程 2 的优先级比线程 1 低应该线程 1 先获得执行。*/
static void thread2_mp_release(void *parameter)
{int i;rt_kprintf(thread2 try to release block\n);for (i 0; i 50 ; i){/* 释放所有分配成功的内存块 */if (ptr[i] ! RT_NULL){rt_kprintf(release block %d\n, i);rt_mp_free(ptr[i]);ptr[i] RT_NULL;}}
}int mempool_sample(void)
{int i;for (i 0; i 50; i ) ptr[i] RT_NULL;/* 初始化内存池对象 */rt_mp_init(mp, mp1, mempool[0], sizeof(mempool), 80);/* 创建线程 1申请内存池 */tid1 rt_thread_create(thread1, thread1_mp_alloc, RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY, THREAD_TIMESLICE);if (tid1 ! RT_NULL)rt_thread_startup(tid1);/* 创建线程 2释放内存池 */tid2 rt_thread_create(thread2, thread2_mp_release, RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY 1, THREAD_TIMESLICE);if (tid2 ! RT_NULL)rt_thread_startup(tid2);return 0;
}/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(mempool_sample, mempool sample);