|
发表于 2008-7-30 20:40:57
|
显示全部楼层
貌似比较简单呀。我单凭你贴出来的代码分析的。
空闲空间被分成块。每个块的起始存放着自己的大小和是否被使用的标志。
分配内存的时候根据对齐调整后的size,到不同的内存区域去分配。把当前块的大小和需要分配的size比较,不够就把后面块的空间也算进来。直到可以分配。( do while循环)
分配完之后,如果得到空间大小和size的差值比较大,浪费了一些,就把浪费的空间也做成块。
返回给应用程序前hdr++,表示把大小和使用标志占用的空间保留起来。用户只使用后面的空间。
void *osal_mem_alloc( uint16 size )
{
osalMemHdr_t *prev;
osalMemHdr_t *hdr;
halIntState_t intState;
uint16 tmp;
byte coal = 0;
#if ( OSALMEM_GUARD )
// Try to protect against premature use by HAL / OSAL.
if ( ready != OSALMEM_READY )
{
osal_mem_init();
}
#endif
OSALMEM_ASSERT( size );
/* 调整size,留出管理空间,对齐 */
size += HDRSZ;
// Calculate required bytes to add to 'size' to align to halDataAlign_t.
if ( sizeof( halDataAlign_t ) == 2 )
{
size += (size & 0x01);
}
else if ( sizeof( halDataAlign_t ) != 1 )
{
const byte mod = size % sizeof( halDataAlign_t );
if ( mod != 0 )
{
size += (sizeof( halDataAlign_t ) - mod);
}
}
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
// Smaller allocations are first attempted in the small-block bucket.
/* 不同大小范围的申请,到不同的区间去分配 */
if ( size <= OSALMEM_SMALL_BLKSZ )
{
hdr = ff1;
}
else
{
hdr = ff2;
}
/* 获取当前block的管理数据, 管理数据应该低位表示此区域大小
高位是flag,从这段程序来看就是一个MEM_IN_USE的标志
*/
tmp = *hdr;
do
{
/* 如果此区域正在使用,则跳过,*/
if ( tmp & OSALMEM_IN_USE )
{
tmp ^= OSALMEM_IN_USE; /* tmp = 此区域大小 */
/* 有可能在遇到此区域前,
分配器正在准备联合多个连续的区域组成足够大的空间,
但是中途遇到一个被使用的空间,因此需要重头开始联合
coal就是这个标志
*/
coal = 0;
}
else
{
if ( coal != 0 )
{
#if ( OSALMEM_METRICS )
blkCnt--;
blkFree--;
#endif
/* 累加大小 */
*prev += *hdr;
if ( *prev >= size )
{
/* 足够大了就结束分配 */
hdr = prev;
tmp = *hdr;
break;
}
}
else
{
/* 如果此区域够大,则分配结束 */
if ( tmp >= size )
{
break;
}
/* 不够大,准备联合后面的区域 coal=1表示开始累加后面的空间*/
coal = 1;
prev = hdr;
}
}
hdr = (osalMemHdr_t *)((byte *)hdr + tmp);
tmp = *hdr;
if ( tmp == 0 )
{
hdr = NULL;
break;
}
} while ( 1 );
/* 如果前面分配到了空间 */
if ( hdr != NULL )
{
tmp -= size;
/* tmp 现在是分配到的空间大小-实际需求大小,也就是浪费的空间大小 */
// Determine whether the threshold for splitting is met.
if ( tmp >= OSALMEM_MIN_BLKSZ )
{
/* 浪费太多的话,还是将其标识为自由空间 */
// Split the block before allocating it.
osalMemHdr_t *next = (osalMemHdr_t *)((byte *)hdr + size);
*next = tmp;
/* 把hdr调整为需求大小,然后打上正在使用的标志 */
*hdr = (size | OSALMEM_IN_USE);
#if ( OSALMEM_METRICS )
blkCnt++;
if ( blkMax < blkCnt )
{
blkMax = blkCnt;
}
memAlo += size;
#endif
}
else
{
#if ( OSALMEM_METRICS )
memAlo += *hdr;
blkFree--;
#endif
/* 浪费空间不算大,则直接打正在使用标志 */
*hdr |= OSALMEM_IN_USE;
}
#if ( OSALMEM_METRICS )
if ( memMax < memAlo )
{
memMax = memAlo;
}
#endif
#if ( OSALMEM_PROFILER )
{
byte idx;
size = *hdr ^ OSALMEM_IN_USE;
for ( idx = 0; idx < OSALMEM_PROMAX; idx++ )
{
if ( size <= proCnt[idx] )
{
break;
}
}
proCur[idx]++;
if ( proMax[idx] < proCur[idx] )
{
proMax[idx] = proCur[idx];
}
proTot[idx]++;
}
#endif
hdr++;
#if ( OSALMEM_PROFILER )
osal_memset( (byte *)hdr, OSALMEM_ALOC, (size - HDRSZ) );
/* A small-block could not be allocated in the small-block bucket.
* When this occurs significantly frequently, increase the size of the
* bucket in order to restore better worst case run times. Set the first
* profiling bucket size in proCnt[] to the small-block bucket size and
* divide proSmallBlkMiss by the corresponding proTot[] size to get % miss.
* Best worst case time on TrasmitApp was achieved at a 0-15% miss rate
* during steady state Tx load, 0% during idle and steady state Rx load.
*/
if ( (size <= OSALMEM_SMALL_BLKSZ) && (hdr > ff2) )
{
proSmallBlkMiss++;
}
#endif
}
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.
return (void *)hdr;
} |
|