OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4925|回复: 14

(求助)续[[STM32F7通过ESP8266获得网络时间和天气]]内存管理问题

[复制链接]

13

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2018-12-31
在线时间
47 小时
发表于 2019-3-25 21:05:01 | 显示全部楼层 |阅读模式
20金钱
本帖最后由 danielhuang 于 2019-3-25 21:09 编辑

http://www.openedv.com/forum.php?mod=viewthread&tid=289792&extra=
续上贴
@freethink @wcyingdream

内存管理

内存管理

经过两三天的观察,发现天气在两三个小时后就不再更新了,调用串口看接收天气信息正常,就是LCD不再更新信息。
初步估计是内存资源被耗尽所至。后面调用了内存使用率函数my_mem_perused()查看内存使用情况,便正实我了的想
法。LCD右边红色的四位数字是内存使用率,精度是0.x%。天气程序是初始化后,每一分钟调用函数更新一次,结果内存
资源使用率就在被每次更新后上升0.5%。所以程序会在200分钟后申请不到内存而停止更新。我查看了程序,基本每个
mymalloc  都 myfree 了。现在请求大家帮助看看问题在哪里,谢谢。


//获取一次实时天气
//返回:0---获取成功,1---获取失败
u8 get_current_weather(void)
{
        u8 *p;
        u8 res;
//        u8 ipbuf[16];         //IP缓存
        p=mymalloc(SRAMIN,40);                                                        //申请40字节内存
        sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",WEATHER_SERVERIP,WEATHER_PORTNUM);    //配置目标TCP服务器
        res = atk_8266_send_cmd(p,"OK",200);//连接到目标TCP服务器
        if(res==1)
        {
                myfree(SRAMIN,p);
                return 1;
        }
        delay_ms(300);
        atk_8266_send_cmd("AT+CIPMODE=1","OK",100);      //传输模式为:透传       
//        atk_8266_get_wanip(ipbuf);//获取WAN IP

        USART3_RX_STA=0;
        atk_8266_send_cmd("AT+CIPSEND","OK",100);         //开始透传
        printf("start trans...\r\n");
        u3_printf("GET https://api.seniverse.com/v3/wea ... =zh-Hans&unit=c\n\n");       
        delay_ms(20);//延时20ms返回的是指令发送成功的状态
//        atk_8266_at_response(1);
        USART3_RX_STA=0;        //清零串口3数据
        delay_ms(1000);
//        atk_8266_at_response(0);
        if(USART3_RX_STA&0X8000)                //此时再次接到一次数据,为天气的数据
        {
                USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
        }
        parse_now_weather();

       
        atk_8266_quit_trans();//退出透传
        atk_8266_send_cmd("AT+CIPCLOSE","OK",50);         //关闭连接
        myfree(SRAMIN,p);
        return 0;
}


//解析当前天气
u8 parse_now_weather(void)
{
        cJSON *root;
        cJSON *pSub;
        cJSON *arrayItem;
        cJSON *pItem;
        cJSON *pSubItem;
        cJSON *pChildItem;
       
        char *pr,*utf8str,*gbkstr;
//        u8 size = 0;
        int len;
        u8 res;
        u8 temperature;
       
        root = mymalloc(SRAMIN,sizeof(cJSON));
        pSub = mymalloc(SRAMIN,sizeof(cJSON));
        pItem = mymalloc(SRAMIN,sizeof(cJSON));
        pSubItem = mymalloc(SRAMIN,sizeof(cJSON));
        pChildItem = mymalloc(SRAMIN,sizeof(cJSON));
        arrayItem = mymalloc(SRAMIN,sizeof(cJSON));
       
        pr = mymalloc(SRAMIN,1000);
        utf8str = mymalloc(SRAMIN,50);
        gbkstr = mymalloc(SRAMIN,50);
       
        memset(pr,0,1000);
        memset(gbkstr,0,50);
        memset(utf8str,0,50);
       
        file = mymalloc(SRAMIN,sizeof(FIL));
        res=f_open(file,(const TCHAR*)APP_ASCII_5427,FA_READ);//打开文件
        if(res==FR_OK)
        {
                asc2_5427 = mymalloc(SRAMIN,file->obj.objsize);
                if(asc2_5427 != NULL)
                {
                        res = f_read(file,asc2_5427,file->obj.objsize,&br);
                }
                f_close(file);
        }

        printf("jieshou->1dayjson = %s\r\n",USART3_RX_BUF);
       
        root = cJSON_Parse((const char*)USART3_RX_BUF);
        if(root != NULL)
        {
                pSub = cJSON_GetObjectItem(root,"results");
                if(pSub != NULL)
                {
//                        size = cJSON_GetArraySize(pSub);
                        arrayItem = cJSON_GetArrayItem(pSub,0);  
                        pr = cJSON_Print(arrayItem);   //获取jsom数组
                        pItem = cJSON_Parse(pr);       //对数组,进行升级。
                        if(pItem != NULL)
                        {
                                pSubItem = cJSON_GetObjectItem(pItem,"location");
                                if(pSubItem != NULL)
                                {
                                        pChildItem = cJSON_GetObjectItem(pSubItem,"name");
                                        if(pChildItem != NULL)
                                        {
                                                utf8str = pChildItem->valuestring;
                                                SwitchToGbk((const u8*)utf8str,strlen(utf8str),(u8 *)gbkstr,&len);  //获取城市名称转换为gbk文件
                                                Show_Str(0,0,lcddev.width,lcddev.height,(u8 *)gbkstr,32,0);         //显示城市名称。
                                          printf("定位:%s\r\n",(u8 *)gbkstr);        //自己添加
                                        }
                                }
//                                memset(utf8str,0,50);
                                memset(gbkstr,0,50);
                                pSubItem = cJSON_GetObjectItem(pItem,"now");
                                if(pSubItem != NULL)
                                {
                                        pChildItem = cJSON_GetObjectItem(pSubItem,"text");  //获取天气信息。多云
                                        if(pChildItem != NULL)
                                        {
                                                utf8str = pChildItem->valuestring;
                                                SwitchToGbk((const u8*)utf8str,strlen(utf8str),(u8 *)gbkstr,&len);
                                                POINT_COLOR = GBLUE;
                                                Show_Str(410,40,lcddev.width,lcddev.height,(u8 *)gbkstr,32,0);  //显示多云
                                                LCD_ShowString(410,40,500,32,32,(u8*)gbkstr);
                                                printf("天气:%s\r\n",(u8 *)gbkstr);        //自己添加
                                        }
//                                        memset(utf8str,0,50);
//                                        memset(gbkstr,0,50);
                                       
                                        pChildItem = cJSON_GetObjectItem(pSubItem,"code");              //获取气象代码
                                        if(pChildItem != NULL)
                                        {
                                                gbkstr = pChildItem->valuestring;
                                                show_weather_icon((u8 *)gbkstr,0);                           //根据气象代码,更新图片
                                        }
//                                        memset(gbkstr,0,50);
                                       
                                        pChildItem = cJSON_GetObjectItem(pSubItem,"temperature");     //获取温度信息
                                        if(pChildItem != NULL)
                                        {
                                                gbkstr = pChildItem->valuestring;
                                                temperature = str2int((u8 *)gbkstr);
                                                gui_show_num(280,90,2,RED,54,temperature,0x80);
                                                gui_show_num(610,90,4,RED,54,my_mem_perused(SRAMIN),0x80);
                                                printf("温度:%s\r\n",(u8 *)gbkstr);        //自己添加
                                        }
                        }
               
                        pSubItem = cJSON_GetObjectItem(pItem,"last_update");
                                if(pSubItem != NULL)               
                                {
                                  gbkstr =pSubItem->valuestring;
                                        POINT_COLOR = WHITE;
                                         LCD_ShowString(0,188,300,12,12,(u8*)gbkstr);
                                         printf("最后更新时间: %s\r\n",(u8*)gbkstr);
                                        //LCD_ShowString(60,110,200,16,16,"Font Update Success!");
                                }               
                        }
                        cJSON_Delete(pItem);
                        myfree(SRAMIN,pItem);
                }
        }
        cJSON_Delete(root);
        myfree(SRAMIN,root);
        myfree(SRAMIN,pSub);
        myfree(SRAMIN,pItem);
        myfree(SRAMIN,pSubItem);
        myfree(SRAMIN,pChildItem);
        myfree(SRAMIN,arrayItem);
        myfree(SRAMIN,pr);
        myfree(SRAMIN,utf8str);
        myfree(SRAMIN,gbkstr);
        myfree(SRAMIN,file);
        myfree(SRAMIN,asc2_5427);
        return 0;
}

最佳答案

查看完整内容[请看2#楼]

你都没读懂内存管理的原理。好好去看看原理吧。 只要指针不变,释放的时候,以及使用的时候,释放的时候,是不存在任何问题的。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2019-3-25 21:05:02 | 显示全部楼层
你都没读懂内存管理的原理。好好去看看原理吧。
只要指针不变,释放的时候,以及使用的时候,释放的时候,是不存在任何问题的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2019-3-26 02:19:29 | 显示全部楼层
八成是你申请了,没释放。检查办法,可以在每个函数的入口打印内存使用率,出口打印内存使用率,看下变化,就知道在哪个函数有问题了
回复

使用道具 举报

13

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2018-12-31
在线时间
47 小时
 楼主| 发表于 2019-3-26 07:59:04 | 显示全部楼层
本帖最后由 danielhuang 于 2019-3-26 08:24 编辑
正点原子 发表于 2019-3-26 02:19
八成是你申请了,没释放。检查办法,可以在每个函数的入口打印内存使用率,出口打印内存使用率,看下变化, ...

谢谢,原子哥的建议,我试试。目前是这样例如未调用之前使用率是3.5%,调用时是10.5%,调用完后是4.0% 这样子。我是不明白上升的 0.5% 是产生的内存碎片吗? 因为每次调用函数申请的内存大小和数量都是一样的,系统不能重复利用吗?请问如果我每次调用做到申请了的内存都释放的话,是否可以做到内存使用率在函数调用前后保持不变(内存一点也不会变小)?

回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2019-3-27 02:20:36 | 显示全部楼层
danielhuang 发表于 2019-3-26 07:59
谢谢,原子哥的建议,我试试。目前是这样例如未调用之前使用率是3.5%,调用时是10.5%,调用完后是4.0% 这 ...

只要你每次使用完,都释放了,就不会存在内存泄漏的
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

13

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2018-12-31
在线时间
47 小时
 楼主| 发表于 2019-3-27 14:55:09 | 显示全部楼层
本帖最后由 danielhuang 于 2019-3-27 15:02 编辑
正点原子 发表于 2019-3-27 02:20
只要你每次使用完,都释放了,就不会存在内存泄漏的

已查明,程序运行时申请的内存到调用结束前都有全部释放了。
但因为cjson解释里对一些mymalloc得来的指针值进行了修改或重新的赋值(cjson对象提取),而修改和重新赋值后的指针所指向的数据比原来的少,导致最后myfree时释放的内存变少了,间接导致 "内存泄漏" 。请问原子哥看懂我说的意思吗?请问有什么方法能解决?谢谢
例如:
char *pr;
pr = mymalloc(SRAMIN,1000);
pr = cJSON_Print(arrayItem);   //获取json数组
pItem = cJSON_Parse(pr);       //对普通json串处理成json对象

myfree(SRAMIN,pr);

pr申请时大小为1000字节,但后来由于指针给重新赋值,指向的数据大小已经不再时1000(比1000少,只有300),释放时只有300字节。

请问有什么方法可以处理这个问题??


回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2019-3-28 02:00:15 | 显示全部楼层
danielhuang 发表于 2019-3-27 14:55
已查明,程序运行时申请的内存到调用结束前都有全部释放了。
但因为cjson解释里对一些mymalloc得来的指 ...

不对,这不会导致内存泄漏
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

13

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2018-12-31
在线时间
47 小时
 楼主| 发表于 2019-3-28 10:41:40 | 显示全部楼层
正点原子 发表于 2019-3-28 02:00
不对,这不会导致内存泄漏

会啊,跟这情况是一样的。
https://blog.csdn.net/qq_32319583/article/details/53641469
QQ截图20190328103922a.jpg
QQ截图20190328104132b.jpg
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2019-3-29 02:26:36 | 显示全部楼层
danielhuang 发表于 2019-3-28 10:41
会啊,跟这情况是一样的。
https://blog.csdn.net/qq_32319583/article/details/53641469

你说的这个,根本不是一回事。
如果内存管理,连你申请300个,只用了30个字节,就导致270个泄漏,那就是天大的笑话了。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

18

主题

323

帖子

1

精华

高级会员

Rank: 4

积分
935
金钱
935
注册时间
2017-12-11
在线时间
196 小时
发表于 2019-3-29 09:41:50 | 显示全部楼层
内存指针不能在没释放时,重新申请内存; 内存的释放,是对指针内容数据保存地址的释放;得新分配,之前的地址就没了;也就会因为无法调查,而变成完全自由态的内存,这个内存是不受控的
回复

使用道具 举报

18

主题

323

帖子

1

精华

高级会员

Rank: 4

积分
935
金钱
935
注册时间
2017-12-11
在线时间
196 小时
发表于 2019-3-29 09:46:45 | 显示全部楼层
不但不能没释放就申请,更不能申请之后却忘记申请之后内存地址的保存位置, 对于单向申请,单向释放的内存更加需要注意,比如给某某发消息,收信方必需释放;
回复

使用道具 举报

13

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2018-12-31
在线时间
47 小时
 楼主| 发表于 2019-3-29 10:21:59 | 显示全部楼层
正点原子 发表于 2019-3-29 02:27
你都没读懂内存管理的原理。好好去看看原理吧。
只要指针不变,释放的时候,以及使用的时候,释放的时候, ...

你好原子哥,是的,你说的是对的,我明白你的意思。我是刚开始没搞懂其中的原理,但通过这个实验我有了进步。现在才知道申请与释放的前提是指针指向的地址没发生变化,但实验里的指针申请了内存后指针指向地址的值变了。我现在是没有用malloc来申请内存大小了,就系统自己按实际大小自动分配,保护好指针不能让它的指向有变化,现在内存不泄漏了。谢谢,受教了。
回复

使用道具 举报

13

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2018-12-31
在线时间
47 小时
 楼主| 发表于 2019-3-29 10:23:34 | 显示全部楼层
wlq390934605 发表于 2019-3-29 09:46
不但不能没释放就申请,更不能申请之后却忘记申请之后内存地址的保存位置, 对于单向申请,单向释放的内存 ...

是的,谢谢补充。
回复

使用道具 举报

1

主题

56

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
265
金钱
265
注册时间
2017-10-11
在线时间
79 小时
发表于 2019-9-20 11:55:35 | 显示全部楼层
,不错。有新的发展。
回复

使用道具 举报

7

主题

105

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1031
金钱
1031
注册时间
2016-1-28
在线时间
135 小时
发表于 2020-3-14 22:14:55 | 显示全部楼层
楼主,后来弄得怎样了,能分享下程序么。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-21 16:18

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表