TX_BYTE_POOL结构体用来描述字节池管理结构。
/* Define the byte memory pool structure utilized by the application. */
typedef struct TX_BYTE_POOL_STRUCT
{
/* Define the byte pool ID used for error checking. */
ULONG tx_byte_pool_id;
/* Define the byte pool's name. */
CHAR_PTR tx_byte_pool_name;
/* Define the number of available bytes in the pool. */
ULONG tx_byte_pool_available;
/* Define the number of fragments in the pool. */
ULONG tx_byte_pool_fragments;
/* Define the head pointer of byte pool. */
CHAR_PTR tx_byte_pool_list;
/* Define the search pointer used for initial searching for memory
in a byte pool. */
CHAR_PTR tx_byte_pool_search;
/* Save the start address of the byte pool's memory area. */
CHAR_PTR tx_byte_pool_start;
/* Save the byte pool's size in bytes. */
ULONG tx_byte_pool_size;
/* This is used to mark the owner of the byte memory pool during
a search. If this value changes during the search, the local search
pointer must be reset. */
struct TX_THREAD_STRUCT *tx_byte_pool_owner;
/* Define the byte pool suspension list head along with a count of
how many threads are suspended. */
struct TX_THREAD_STRUCT *tx_byte_pool_suspension_list;
ULONG tx_byte_pool_suspended_count;
/* Define the created list next and previous pointers. */
struct TX_BYTE_POOL_STRUCT
*tx_byte_pool_created_next,
*tx_byte_pool_created_previous;
} TX_BYTE_POOL;
域 | 意义 |
---|---|
tx_byte_pool_id | 字节内存池id |
tx_byte_pool_name | 字节内存池名字 |
tx_byte_pool_available | 字节内存池可分配字节 |
tx_byte_pool_fragments | 字节内存池块个数 |
tx_byte_pool_list | 字节内存池头list指针 |
tx_byte_pool_search | 字节内存池开始搜索起始地址 |
tx_byte_pool_start | 字节内存池所在内存空间起始地址 |
tx_byte_pool_size | 字节内存池大小 |
tx_byte_pool_owner | 字节内存池所属线程 |
tx_byte_pool_suspension_list | 挂起线程链表 |
tx_byte_pool_created_next | 指向下一个字节内存池指针 |
tx_byte_pool_created_previous | 指向前一个字节内存池指针 |
系统中所有创建的字节内存池都插入到链表_tx_byte_pool_created_ptr。tx_byte_pool_created_next指向下一个字节内存池指针,tx_byte_pool_created_previous指向前一个字节内存池指针。
应用开发者指定字节内存池起始地址和大小,调用_tx_byte_pool_create创建内存池。
内存池初始化为一个大的块和一个小的控制块两部分,小的控制块只是为了fisrt-fit算法,不会分配给应用使用。
内存池中不同块(block)之间通过单向链表连接,但没有专门定义链表指针,而是利用每块内存头部前8个字节作为控制字段,前4个字节指向下一个内存块的起始地址,随后4个字节作为内存是否分配标志,如果已经被分配,指向内存池TX_BYTE_POOL结构指针,如果空闲设置为TX_BYTE_BLOCK_FREE。
最后一块内存池只有8个字节,作为控制块,前4个字节指向内存池TX_BYTE_POOL结构指针,后4个字节设置为TX_BYTE_BLOCK_ALLOC。
#define TX_BYTE_BLOCK_ALLOC 0xAAAAAAAAUL
#define TX_BYTE_BLOCK_FREE 0xFFFFEEEEUL
如下图,pool_ptr指向TX_BYTE_POOL内存池管理结构,整个内存分为两块,TX_BYTE_POOL中tx_byte_pool_start指向内存池首地址。第一块中的前4个字节存储第二块(最后一块,控制块)的起始地址,后四个字节设置为TX_BYTE_BLOCK_FREE,因为还没有使用,标记为空闲块。
第二块(最后一块,控制块)的前4个字节存放指向内存池起始地址tx_byte_pool_start,后4字节标记为TX_BYTE_BLOCK_ALLOC 标记为已分配,也表示最后一块。
tx_byte_pool_search指向搜索内存时的开始地址。
这样内存块就构成了单向循环链表。
_tx_byte_allocate函数用来内存分配。
内存分配使用首次适应(fisrt-fit)算法,从上次操作的空闲内存块开始查找,找到大小合适内存,返回成功。
查找到第一个大于请求分配大小的内存块时,就认为找到了,把这个大的内存块分为两个内存块,前一个返回应用程序使用,后一个内存块挂入内存管理链表中。
初始化时,内存块只有两个,随着分配内存和释放内存,会出现很多小的内存块,称为内存碎片。
查找过程中,发现两个邻居内存块是地址连续的,那么把这两个内存块合并成为一个内存块,称为内存整理。
如果内存池没有足够可用内存,申请分配内存的线程会挂起。
举例:
下图为第一次分配内存后,最初的第一块内存被分为了两块:第一块和第二块。
第一块返回给应用程序,第一块前面8个字节由于是控制字段,所以返回应用程序的内存起始地址跨过了前面8个字节,memptr指向分配的地址。第一块的前4字节存储第二块内存起始地址,随后4个字节指向了内存池管理结构,标志着第一块内存已经被占用,不是空闲内存了。
第二块内存前4个字节指向第三块内存(最后一块内存),继续构成单向链表。随后4个字节存储TX_BYTE_BLOCK_FREE,表示还是空闲内存块。
tx_byte_pool_search指向搜索内存时的开始地址,第一块已经被占用,所以指向了第一个空闲的内存块,即第二块内存起始地址。
如下图,第二次分配内存。
从上图中第一个空闲的内存块(第二块)开始搜索,找到了合适大小,由于请求大小小于空闲的内存块大小,所以把空闲块再次分为两块,如下图所示。
第二块是分配给应用程序的,memptr为返回地址,第二块内存的前4字节指向第三块内存首地址,随后4个字节指向了内存池管理结构,表示这块内存已经被占用。
第三块内存,前4字节指向第四块内存(最后一块内存),继续构成单向链表。随后4个字节存储TX_BYTE_BLOCK_FREE,表示还是空闲内存块。
_tx_byte_release函数用来内存释放。
内存释放时,根据释放内存首地址,减8,计算出内存块控制字段的首地址,通过前四字节找到内存池管理结构指针,可以进行内存释放操作。
释放后,4到8字节存储TX_BYTE_BLOCK_FREE表示为空闲内存块。
这里第二块内存和第三块内存虽然是连续的,但并没有进行合并或内存整理。什么时间合并呢?
等到申请内存分配,发现请求大小大于第二块的大小,开始查找第三块时,这时发现第二块和第三块内存连续,就把第二块和第三块合并为一块。
释放内存后,会检查挂起链表中是否有线程,如果有尝试分配内存并恢复线程执行。线程恢复是按照FIFO顺序恢复,并没有按照线程优先级高低顺序。但是可以在线程释放前调用_tx_byte_pool_prioritize,把最高优先级线程移动到挂起链表最前面,从而先恢复最高优先级线程。
内存在多次分配和释放后,可能会出现大量小的内存块,这种想象成为内存碎片化。
当需要分配一个较大内存时,每次可能需要先遍历大量小内存,这样会使查找开销增加,算法性能下降。由于每个内存块都占用8个字节的控制字段,大量小内存会导致内存的浪费。
查找过程中,发现两个邻居内存块是地址连续的,那么把这两个内存块合并成为一个内存块,称为内存整理。内存整理能够提升算法性能,但提升有限。其它优化方式,可以从查找算法进行优化,如二叉树查找等。
内存整理举例:
假设下图为多次内存分配和释放后的结构,第一块被占用,第二块,第三块,第四块为空闲内存块。
第二块大小为64字节,第三块大小为64字节,第四块内存大小为256字节。
假如现在申请分配内存大小为128字节,在分配查找过程中,发现第二块太小不满足,但第二块和第三块地址连续,于是把第二块和第三块合并为一块,并且发现合并后正好满足请求,返回给应用程序,如下面第二个图。
函数 | 描述 |
---|---|
tx_byte_pool_create | 创建内存字节池 |
tx_byte_pool_delete | 删除内存字节池 |
tx_byte_allocate | 分配内存字节 |
tx_byte_release | 释放内存 |
_tx_byte_pool_info_get | 获得内存池信息 |
_tx_byte_pool_prioritize | 调整内存池挂起链表最前面为最高优先级线程 |
字节内存池使用比较灵活,但也会出现内存碎片问题,导致搜索开销大,系统性能下降,特别是由于小内存多导致线程申请不到足够内存自我挂起,将严重影响系统实时性。
实时系统中,应用程序通常会根据应用使用内存空间,单独创建内存管理算法,通过测试,保证永远不会出现内存不够挂起问题。
字节内存池创建,初始化内存池,把内存池插入_tx_byte_pool_created_ptr链表。
pool_start为内存池的起始地址,pool_size为内存池大小
UINT _tx_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start,
ULONG pool_size)
{
TX_INTERRUPT_SAVE_AREA
TX_BYTE_POOL *tail_ptr; /* Working byte pool pointer */
CHAR_PTR block_ptr; /* Working block pointer */
/* Round the pool size down to something that is evenly divisible by
an ULONG. */
#def 内存池大小 sizeof(ULONG)个字节对齐
pool_size = (pool_size / sizeof(ULONG)) * sizeof(ULONG);
/* Setup the basic byte pool fields. */
#def 初始化参数
pool_ptr -> tx_byte_pool_name = name_ptr;
pool_ptr -> tx_byte_pool_suspension_list = TX_NULL;
pool_ptr -> tx_byte_pool_suspended_count = 0;
/* Save the start and size of the pool. */
#def 保存内存池起始地址和内存大小
pool_ptr -> tx_byte_pool_start = (CHAR_PTR) pool_start;
pool_ptr -> tx_byte_pool_size = pool_size;
/* Setup memory list to the beginning as well as the search pointer. */
#def 设置内存链表首地址,内存池搜索起始地址
pool_ptr -> tx_byte_pool_list = (CHAR_PTR) pool_start;
pool_ptr -> tx_byte_pool_search = (CHAR_PTR) pool_start;
/* Initially, the pool will have two blocks. One large block at the
beginning that is available and a small allocated block at the end
of the pool that is there just for the algorithm. Be sure to count
the available block's header in the available bytes count. */
#def 设置可用内存大小,总的大小减去控制字段
pool_ptr -> tx_byte_pool_available = pool_size - sizeof(VOID_PTR) - sizeof(ULONG);
#def 内存池最开始初始化为两块,一个大的块用于分配内存;一个小的固定块,仅用于内存分配算法计算
pool_ptr -> tx_byte_pool_fragments = 2;
/* Calculate the end of the pool's memory area. */
#def 指向内存池最后地址
block_ptr = ((CHAR_PTR) pool_start) + (UINT) pool_size;
/* Backup the end of the pool pointer and build the pre-allocated block. */
#def 内存池最后一块,最后4字节存储TX_BYTE_BLOCK_ALLOC
block_ptr = block_ptr - sizeof(ULONG);
*((ULONG_PTR) block_ptr) = TX_BYTE_BLOCK_ALLOC;
#def 内存池最后一块,前面4字节存储pool_start内存池起始地址
block_ptr = block_ptr - sizeof(CHAR_PTR);
*((CHAR_PTR *) block_ptr) = pool_start;
/* Now setup the large available block in the pool. */
#def 内存池第1块,最前面4字节存储第二块内存的首地址
*((CHAR_PTR *) pool_start) = block_ptr;
block_ptr = (CHAR_PTR) pool_start;
block_ptr = block_ptr + sizeof(CHAR_PTR);
#def 随后4字节存储TX_BYTE_BLOCK_FREE,指示为空闲块
*((ULONG_PTR) block_ptr) = TX_BYTE_BLOCK_FREE;
/* Clear the owner id. */
pool_ptr -> tx_byte_pool_owner = TX_NULL;
/* Disable interrupts to place the byte pool on the created list. */
TX_DISABLE
/* Setup the byte pool ID to make it valid. */
#def 内存池有效
pool_ptr -> tx_byte_pool_id = TX_BYTE_POOL_ID;
/* Place the byte pool on the list of created byte pools. First,
check for an empty list. */
#def 把内存池插入_tx_byte_pool_created_ptr list
if (_tx_byte_pool_created_ptr)
{
/* Pickup tail pointer. */
tail_ptr = _tx_byte_pool_created_ptr -> tx_byte_pool_created_previous;
/* Place the new byte pool in the list. */
_tx_byte_pool_created_ptr -> tx_byte_pool_created_previous = pool_ptr;
tail_ptr -> tx_byte_pool_created_next = pool_ptr;
/* Setup this byte pool's created links. */
pool_ptr -> tx_byte_pool_created_previous = tail_ptr;
pool_ptr -> tx_byte_pool_created_next = _tx_byte_pool_created_ptr;
}
else
{
/* The created byte pool list is empty. Add byte pool to empty list. */
_tx_byte_pool_created_ptr = pool_ptr;
pool_ptr -> tx_byte_pool_created_next = pool_ptr;
pool_ptr -> tx_byte_pool_created_previous = pool_ptr;
}
/* Increase the byte pool created count. */
_tx_byte_pool_created_count++;
/* Restore interrupts. */
TX_RESTORE
/* Return TX_SUCCESS. */
return (TX_SUCCESS);
}
把内存池从_tx_byte_pool_created_ptr链表删除,恢复挂起链表中的线程。
UINT _tx_byte_pool_delete(TX_BYTE_POOL *pool_ptr)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *thread_ptr; /* Working thread pointer */
/* Disable interrupts to remove the byte pool from the created list. */
TX_DISABLE
/* Decrease byte pool created count. */
_tx_byte_pool_created_count--;
/* Clear the byte pool ID to make it invalid. */
#def 设置为无效
pool_ptr -> tx_byte_pool_id = 0;
/* See if the byte pool is the only one on the list. */
#def 从_tx_byte_pool_created_ptr 链表删除内存
if (pool_ptr == pool_ptr -> tx_byte_pool_created_next)
{
/* Only created byte pool, just set the created list to NULL. */
_tx_byte_pool_created_ptr = TX_NULL;
}
else
{
/* Link-up the neighbors. */
(pool_ptr -> tx_byte_pool_created_next) -> tx_byte_pool_created_previous =
pool_ptr -> tx_byte_pool_created_previous;
(pool_ptr -> tx_byte_pool_created_previous) -> tx_byte_pool_created_next =
pool_ptr -> tx_byte_pool_created_next;
/* See if we have to update the created list head pointer. */
if (_tx_byte_pool_created_ptr == pool_ptr)
/* Yes, move the head pointer to the next link. */
_tx_byte_pool_created_ptr = pool_ptr -> tx_byte_pool_created_next;
}
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Walk through the byte pool list to resume any and all threads suspended
on this byte pool. */
thread_ptr = pool_ptr -> tx_byte_pool_suspension_list;
#def 遍历挂起链表,恢复线程
while (pool_ptr -> tx_byte_pool_suspended_count)
{
/* Lockout interrupts. */
TX_DISABLE
/* Clear the cleanup pointer, this prevents the timeout from doing
anything. */
thread_ptr -> tx_suspend_cleanup = TX_NULL;
/* Temporarily disable preemption again. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Yes, deactivate the thread's timer just in case. */
#def 关闭定时器
_tx_timer_deactivate(&(thread_ptr -> tx_thread_timer));
/* Clear the remaining time to ensure timer doesn't get activated. */
thread_ptr -> tx_thread_timer.tx_remaining_ticks = 0;
/* Set the return status in the thread to TX_DELETED. */
thread_ptr -> tx_suspend_status = TX_DELETED;
/* Move the thread pointer ahead. */
thread_ptr = thread_ptr -> tx_suspended_next;
/* Resume the thread. */
#def 恢复线程
_tx_thread_resume(thread_ptr -> tx_suspended_previous);
/* Decrease the suspended count. */
pool_ptr -> tx_byte_pool_suspended_count--;
}
/* Disable interrupts. */
TX_DISABLE
/* Release previous preempt disable. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
/* Check for preemption. */
#def 恢复线程后,可能有高优先级线程,切换调度
if (_tx_thread_current_ptr != _tx_thread_execute_ptr)
/* Transfer control to system. */
_tx_thread_system_return();
/* Return TX_SUCCESS. */
return (TX_SUCCESS);
}