• 【华为云技术分享】容易造成单片机内存溢出的几个陷阱


    【摘要】 关于程序变量和内存分配,都是需要我们时刻关注的问题。我相信有不少人在这块犯过很多的错误,也可能说明我们基础不够扎实,编写程序的习惯也不够好。 总结一下关于程序的变量和内存方面的概念,虽然是属于C语言方面非常基础的知识,但是工作中一不小心还是会发生一些内存泄漏、内存溢出之类的问题。所以自己对这块的理解也还远远不够。在这总结一下关于这方面的知识点,用来互相学习,更用来提醒自己,并作为自己的一个经验总结。

    总结一下关于程序的变量,和内存方面的概念,虽然是属于C语言方面非常基础的知识,但是工作中一不小心还是会发生一些内存泄漏、内存溢出之类的问题。所以自己对这块的理解也还远远不够。在这总结一下关于这方面的知识点,用来互相学习,更用来提醒自己,并作为自己的一个经验总结。

    我们知道我们的程序一般是储存在flash里面的,但是运行的时候是在内存(RAM)里运行的,我们的程序一般有这么几个部分组成:宏定义、变量、常量、动态区、程序代码。

    我们通过下面这个Demo程序来了解一下程序在运行的时候,这些部分大概都在内存中的哪些地方。

     1  #define OFF 0x00          //宏定义不占用内存空间,宏在预处理阶段会被替换掉,执行文件中并不存在宏定义.
     2  float Num = 3.14;         //全局变量,存在于“变量区”
     3  char* str = NULL;         //全局变量,存在于“变量区”
     4  int main()
     5  {
     6      int time;               //局部变量,存在于“栈区”
     7      char* path = "C:\Users";   //字符串常量,存在于“常量区”
     8      int Users_Num[8];       //局部变量,存在于“栈区”
     9      srt = (char*)malloc(10);    //申请动态存储区,存储于“堆区”
    10      static flaot con = 1.0;   //静态局部变量,存在于“变量区”
    11      
    12      //程序代码区
    13    delay_ms(time);                  //time未初始化,该变量为垃圾值
    14    strcap(str,"Hello World");   //字符串“hello World”比str申请的内存空间大,造成访问越界
    15    free(str);                        //释放str内存
    16    str = NULL;                    //使str指针指向空地址,方便下次使用
    17  }

    访问越界:

    Demo程序上的strcap()语句出现后面字符串大小比前面str变量申请的空间内存大小大的情况就会出现访问越界的情况。写程序时尤其要关注那个字符串它到底有多长,一定要去留意一下。如果出现访问越界的问题有些编译器是可能识别不出来的,但确实会造成这个内存访问错误,除此之外还有一些类似的:比如像sprintf(),strcat()等函数都有可能会导致访问越界的情况发生。

    还有就是数组,数组也是特别容易造成访问越界的,有些编译器可能会检测数组长度是否超出数组下标长度,但有的地方未必就能检测出,如将数组在for()循环里访问的,这个时候就需要注意了,千万小心不要让它出现访问越界的情况。因为编译是检测不出来的,但是在运行的时候就会出现内存访问的故障了。

    栈区:

    根据上面Demo程序写的我们知道局部变量是存在于“栈区”的,所以一般我们的局部变量通常不要定义的太大,尤其是一些数组变量,如果说非常大,就会占用非常大的栈区空间,那么这在程序运行的时候非常容易出现栈溢出。平常我们程序里不可避免的会调用一些函数,所以我们调用一些函数的时候最好不要有深层次的调用,因为在调用函数的过程中栈区会不停的存储函数相关的一些变量和一些地址。所以需要深层次的函数递归调用的时候,大家尽量采用别的方式去代替。

    堆区:

    当申请了动态区域,用完的时候一定要记得释放(free),如果没有释放,那么这块内存区域就将处于不可用状态(就像占着茅坑不拉屎一样),程序大了或运行久了就极有可能会导致内存的泄露(重启一下就能解决90%的问题根源),同时我们在释放的时候也要注意释放的内存只能释放一次,不要重复的释放,有的时候代码量会比较大,所以有可能会在不止一处地方进行了代码的释放操作。因为我们内存释放了一次后,该内存区域就有可能用来做别的事了,如果这时候我们又再释放一遍就很有可能会出现问题了。释放完之后最好把指针指向空地址,避免下次再使用指针的时候出现地址的错误。

    以上都是我们平时在开发的过程中需要格外注意的。有了这么一个概念之后再写代码或者在规划代码的时候,心里能够有个数,我们知道这些东西都大概在内存的哪个地方,这样就会尽量的去避免出现内存溢出或泄露的问题。也能够提高我们代码的效率。

    像关于程序变量和内存分配,都是需要我们时刻关注的问题。我相信有不少人在这块犯过很多的错误,也可能说明我们基础不够扎实,编写程序的习惯也不够好。(但可能也有人受不了内存泄漏的折磨,而开发了“自动垃圾回收机制gc”,然后就有了Java)

    HDC.Cloud 华为开发者大会2020 即将于2020年2月11日-12日在深圳举办,是一线开发者学习实践鲲鹏通用计算、昇腾AI计算、数据库、区块链、云原生、5G等ICT开放能力的最佳舞台。

    欢迎报名参会https://www.huaweicloud.com/HDC.Cloud.html?utm_source=&utm_medium=&utm_campaign=&utm_content=techcommunity

  • 相关阅读:
    PHP foreach 循环
    C#导出Excel时间格式问题
    vs2015 key
    C# 的Chart
    线程暂停与继续实现
    CCNA网络工程师学习进程(2)基本的网络设备
    CCNA网络工程师学习进程(1)网络的基本概述
    安卓学习进程(3)安卓开发工具的简介
    安卓学习进程(2)Android开发环境的搭建
    安卓学习进程(1)移动平台开发的简介
  • 原文地址:https://www.cnblogs.com/huaweicloud/p/12229679.html
Copyright © 2020-2023  润新知