今天在做FreeRTOS的剩余堆栈统计的时候,发现了一个让我很困惑的问题:同一个简单的亮灯的程序,使用FreeRTOS自带的高水位线函数获取剩余内存时,得到的剩余内存是4。而使用IAR自带的插件来统计的时候,剩余内存是16。于是我进行了如下是测试试验
首先测试用的代码很简单:一个普通的亮灯程序:
//LED0任务函数
void led0_task(void *pvParameters)
{
while(1)
{
LED1_TOG;
vTaskDelay(500);
}
}
检测历史剩余最小堆栈用的是FreeRTOS自带的uxTaskGetSystemState()函数,写在一个检测任务里,顺带着把其他的一些任务名之类参数打印了出来:
void TaskSta_task(void *pvParameters)
{
UBaseType_t ArraySize;
TaskStatus_t *StatusArray;
uint8_t x;
ArraySize = uxTaskGetNumberOfTasks(); //获取任务个数
StatusArray = pvPortMalloc(ArraySize*sizeof(TaskStatus_t));
while(1)
{
LED4_TOG;
if(StatusArray != NULL){ //内存申请成功
ArraySize = uxTaskGetSystemState( (TaskStatus_t *) StatusArray,
(UBaseType_t ) ArraySize,
(uint32_t * ) &FreeRTOSRunTimeTicks );
RTT_printf(0,"TaskName\t\t\tPriority\t\tTaskNumber\t\tMinStk\t\t\n");
for(x = 0;x<ArraySize;x++){
RTT_printf(0,"%s\t\t\t%d\t\t\t%d\t\t\t%d\t\t%d\r\n",
StatusArray[x].pcTaskName,
(int)StatusArray[x].uxCurrentPriority,
(int)StatusArray[x].xTaskNumber,
(int)StatusArray[x].usStackHighWaterMark,
(int)((float)StatusArray[x].ulRunTimeCounter/FreeRTOSRunTimeTicks*100));
}
RTT_printf(0,"\n\n");
}
vTaskDelay(2000);
}
}
数据的输出使用的是Jlink自带的RTT来进行打印。
就在上面的程序上,使用FreeRTOS自带函数检测到的信息是这样的:
可以看到,led0任务最小剩余堆栈是4
而通过IAR统计出来的的信息是这样的:
它得到的剩余大小是16,刚好是FreeRTOS统计的四倍。
好像是可以得到初步结论:FreeRTOS统计的剩余堆栈大小是按字(4个字节)来统计的,而IAR是按照字节来统计的。
接着我又做了下面这样的的事情,在led0的任务里面定义了一个uint8_t类型的数组并且什么都没干,开始的时候只有一个元素,FreeRTOS和IAR的统计如下:
//LED0任务函数
void led0_task(void *pvParameters)
{
uint8_t i[1];
while(1)
{
LED1_TOG;
vTaskDelay(500);
}
}
可以看到,两边都没有显示有堆栈的占用,并且随着我不停的加大数组的大小,剩余堆栈都没有变小。
接着我又从数组大小是1开始,这次我给了数组一个初值为0,这个时候堆栈发生了变化。FreeRTOS统计的剩余堆栈大小为2,而IAR统计出来的是8。
//LED0任务函数
void led0_task(void *pvParameters)
{
uint8_t i[1] = {0};
while(1)
{
LED1_TOG;
vTaskDelay(500);
}
}
第二个能看到的结论是:一个数据定义了之后不使用是不占用堆栈空间的,不知道是不是编译器的优化,但是给了初值之后就占用空间了。
我的第一个疑惑出现了:我定义的是uint8_t的数组,并且只有一个元素,占用的空间应该是1个字节才对,而无论是FreeRTOS的统计函数,函数IAR的统计都表明堆栈空间一下子少了8个字节。
于是我又接着往上增加数组的大小
//LED0任务函数
void led0_task(void *pvParameters)
{
uint8_t i[8] = {0};
while(1)
{
LED1_TOG;
vTaskDelay(500);
}
}
一直增加到uint8_t i[8] = {0};的时候,统计到的剩余堆栈大小都没有改变,然后增加到uint8_t i[9] = {0};的时候发生了改变,统计到的信息一下子就变成了这样:
两边都变成了0,说明统计到的堆栈剩余大小都没有了,又有8个字节的堆栈没了
到这里我有了一个猜测:也许FreeRTOS的剩余堆栈统计是按照8个字节来算的?一旦申请的空间小于8个字节那些空余的字节就会浪费掉?就像上面的测试一样,是使用了uint8_t i[1] = {0};却花费了8个字节的空间,7个字节的空间就浪费掉了。
于是我接着往下做试验,考虑到使用的是数组,占用 但是连续空间,于是我改变为使用单独变量进行测试:
//LED0任务函数
void led0_task(void *pvParameters)
{
uint8_t i = 0;
while(1)
{
LED1_TOG;
vTaskDelay(500);
}
}
得到的结果是这样的,单独声明一个uint8_t i = 0;还是耗费了8个字节的堆栈大小:
再增加一个uint8_t j = 0;
//LED0任务函数
void led0_task(void *pvParameters)
{
uint8_t i = 0;
uint8_t j = 0;
while(1)
{
LED1_TOG;
vTaskDelay(500);
}
}