【FreeRTOS学习】FreeRTOS的剩余堆栈统计问题

今天在做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);
    }
} 

得到的剩余堆栈空间还是没有改变。

将uint8_t j = 0;更改为float j = 0;得到的剩余堆栈空间还是没有改变。

又将float j = 0; 更改为double j = 0;那么占用的空间就应该是8+1=9个字节,于是统计到的剩余堆栈又变成了0。

于是有了猜测2:其实堆栈空间并没有浪费,只是FreeRTOS和IAR的统计函数出现了问题,他们测到的堆栈变化是已8个字节为单位进行改变的?就像上面所测到的一样:当只用了一个字节的时候,统计到的剩余堆栈减少了8个字节,而占用的空间<=8的时候统计到的信息是不会变化的,一旦占用的空间为9的实现统计到的信息就为又在之前的基础上减少了8个字节。

经过上面的测试,我个人得到的结论是:无论FreeRTOS还是IAR测到的剩余堆栈都是不准的,最多会有7个字节的误差,当然得到的数值越小,所剩余的堆栈越小是对的。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值