我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何解决C程序中Ubuntu、stm32的内存分配问题

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何解决C程序中Ubuntu、stm32的内存分配问题

这篇文章主要介绍了如何解决C程序中Ubuntu、stm32的内存分配问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

    一、内存分区概念介绍

    1.1、C/C++编译程序的内存占用

    栈区(stack)
    由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
    2、堆区(heap)
    一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 。它与数据结构中的堆不同,分配方式类似于链表。
    3、全局区(静态区)(static)
    全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量、未初始化的静态变量在相邻的另一块区域。当程序结束后,变量由系统释放 。
    4、文字常量区
    存放常量字符串。当程序结束后,常量字符串由系统释放 。
    5、程序代码区
    存放函数体的二进制代码。

    从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

    在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
    3、从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

    1.2、栈和堆、全局/静态存储区和常量存储区的对比

    如何解决C程序中Ubuntu、stm32的内存分配问题

    栈区: 主要用来存放局部变量, 传递参数, 存放函数的返回地址。.esp 始终指向栈顶, 栈中的数据越多, esp的值越小。

    堆区: 用于存放动态分配的对象, 当你使用 malloc和new 等进行分配时,所得到的空间就在堆中。动态分配得到的内存区域附带有分配信息, 所以你能够 free和delete它们。

    数据区: 全局,静态和常量是分配在数据区中的,数据区包括bss(未初始化数据区)和初始化数据区。  

    注意: 堆向高内存地址生长; 栈向低内存地址生长; 堆和栈相向而生,堆和栈之间有个临界点,称为stkbrk。

    1.3、图片说明

    如何解决C程序中Ubuntu、stm32的内存分配问题 

    补充:

    Stack: 栈,存放Automatic Variables,按内存地址由高到低方向生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。
    Heap: 堆,自由申请的空间,按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。
    每个线程都会有自己的栈,但是堆空间是共用的。

    参考文献:https://www.icode9.com/content-1-772915.html 

     二、C语言编程论证

    1.1、Ubuntu测试代码实现

    main.c:

    #include <stdio.h>#include <stdlib.h>//定义全局变量int init_global_a = 1;int uninit_global_a;static int inits_global_b = 2;static int uninits_global_b;void output(int a){printf("hello");printf("%d",a);printf("\n");} int main( ){   //定义局部变量int a=2;static int inits_local_c=2, uninits_local_c;    int init_local_d = 1;    output(a);    char *p;    char str[10] = "lyy";    //定义常量字符串    char *var1 = "1234567890";    char *var2 = "qwertyuiop";    //动态分配    int *p1=malloc(4);    int *p2=malloc(4);    //释放    free(p1);    free(p2);    printf("栈区-变量地址\n");    printf("                a:%p\n", &a);    printf("                init_local_d:%p\n", &init_local_d);    printf("                p:%p\n", &p);    printf("              str:%p\n", str);    printf("\n堆区-动态申请地址\n");    printf("                   %p\n", p1);    printf("                   %p\n", p2);    printf("\n全局区-全局变量和静态变量\n");    printf("\n.bss段\n");    printf("全局外部无初值 uninit_global_a:%p\n", &uninit_global_a);    printf("静态外部无初值 uninits_global_b:%p\n", &uninits_global_b);    printf("静态内部无初值 uninits_local_c:%p\n", &uninits_local_c);    printf("\n.data段\n");    printf("全局外部有初值 init_global_a:%p\n", &init_global_a);    printf("静态外部有初值 inits_global_b:%p\n", &inits_global_b);    printf("静态内部有初值 inits_local_c:%p\n", &inits_local_c);    printf("\n文字常量区\n");    printf("文字常量地址     :%p\n",var1);    printf("文字常量地址     :%p\n",var2);    printf("\n代码区\n");    printf("程序区地址       :%p\n",&main);    printf("函数地址         :%p\n",&output);    return 0;}

    使用命令创建一个 main.c 文件:

    gedit main.c

    复制粘贴上述代码

    编译执行

    gcc main.c -o main

    ./main

    分析说明:可以从上图可以得出栈区内存地址由高到低方向生长,堆区内存地址由低到高方向生长。而且整个程序的内存也是从高到低的地址进行分配的。 

     1.2、STM32验证代码实现

    打开之前做过的串口通讯实验代码,在其中进行修改,后面我也会给出先关串口链接

    代码更改

    修改bsp_usart.h :

    添加头文件:

    #include <stdio.h>#include <stdlib.h>

    如何解决C程序中Ubuntu、stm32的内存分配问题

     修改bsp_usart.c :

    重写 fputc 函数:

    int fputc(int ch, FILE *f){USART_SendData(DEBUG_USARTx, (uint8_t)ch);while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);return (ch);}

    如何解决C程序中Ubuntu、stm32的内存分配问题

    main.c : 

    #include "stm32f10x.h"#include "bsp_usart.h"  //添加 bsp_usart.h 头文件 int init_global_a = 1;int uninit_global_a;static int inits_global_b = 2;static int uninits_global_b; void output(int a){printf("hello");printf("%d",a);printf("\n");} int main(void){//定义局部变量int a=2;static int inits_local_c=2, uninits_local_c;int init_local_d = 1;char *p;char str[10] = "lyy";//定义常量字符串char *var1 = "1234567890";char *var2 = "qwertyuiop";//动态分配int *p1=malloc(4);int *p2=malloc(4);USART_Config();//串口初始化output(a);//释放free(p1);free(p2);printf("栈区-变量地址\n");printf("                a:%p\n", &a);printf("                init_local_d:%p\n", &init_local_d);printf("                p:%p\n", &p);printf("              str:%p\n", str);printf("\n堆区-动态申请地址\n");printf("                   %p\n", p1);printf("                   %p\n", p2);printf("\n全局区-全局变量和静态变量\n");printf("\n.bss段\n");printf("全局外部无初值 uninit_global_a:%p\n", &uninit_global_a);printf("静态外部无初值 uninits_global_b:%p\n", &uninits_global_b);printf("静态内部无初值 uninits_local_c:%p\n", &uninits_local_c);printf("\n.data段\n");printf("全局外部有初值 init_global_a:%p\n", &init_global_a);printf("静态外部有初值 inits_global_b:%p\n", &inits_global_b);printf("静态内部有初值 inits_local_c:%p\n", &inits_local_c);printf("\n文字常量区\n");printf("文字常量地址     :%p\n",var1);printf("文字常量地址     :%p\n",var2);printf("\n代码区\n");printf("程序区地址       :%p\n",&main);printf("函数地址         :%p\n",&output);return 0;}

    编译输出

    烧录

    打开串口调试助手,打开串口后,按一下 RESET 键,显示结果:

    如何解决C程序中Ubuntu、stm32的内存分配问题

     4、分析说明

       与Ubuntu一样,stm32的栈区的地址值是从上到下减小的,堆区则是从上到下增长的。从每个区来看,地址值是从上到下逐步减小的,即栈区的地址是高地址,代码区的地址是处于低地址。

    1.3、keil下stm32存储观察

    stm32数据的存储位置

    RAM(随机存取存储器)
    存储的内容可通过指令随机读写访问。RAM中的存储的数据在掉电是会丢失,因而只能在开机运行时存储数据。其中RAM又可以分为两种,一种是Dynamic RAM(DRAM动态随机存储器),另一种是Static RAM(SRAM,静态随机存储器)。栈、堆、全局区(.bss段、.data段)都是存放在RAM中。
    2、ROM(只读存储器)
    只能从里面读出数据而不能任意写入数据。ROM与RAM相比,具有读写速度慢的缺点。但由于其具有掉电后数据可保持不变的优点,因此常用也存放一次性写入的程序和数据,比如主版的BIOS程序的芯片就是ROM存储器。代码区和常量区的内容是不允许被修改的,所以存放于ROM中。

    查看:

    如何解决C程序中Ubuntu、stm32的内存分配问题

    分析说明:

        从图片中可以看出ROM的地址分配是从0x8000000开始,整个大小为0x40000,这个部分用于存放代码区和文字常量区。RAM的地址分配是从0x20000000开始,其大小是0xC000,这个区域用来存放栈、堆、全局区(.bss段、.data段)。与代码结果显示进行对比,也可以看出对应得部分得地址与设置的是相对应的。 

    感谢你能够认真阅读完这篇文章,希望小编分享的“如何解决C程序中Ubuntu、stm32的内存分配问题”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网行业资讯频道,更多相关知识等着你来学习!

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    如何解决C程序中Ubuntu、stm32的内存分配问题

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    如何解决C程序中Ubuntu、stm32的内存分配问题

    这篇文章主要介绍了如何解决C程序中Ubuntu、stm32的内存分配问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、内存分区概念介绍1.1、C/C++编译程序的内存占用
    2023-06-22

    如何分析C语言在STM32中的内存分配问题

    今天就跟大家聊聊有关如何分析C语言在STM32中的内存分配问题,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。01、前言不说废话,先上示例代码uint8_t num_byte[4];u
    2023-06-22

    C++中内存泄漏问题的分析与解决方案

    C++中内存泄漏问题的分析与解决方案概述:内存泄漏是指程序在动态分配内存后,没有及时释放导致内存无法再被程序使用的情况。在C++开发中,内存泄漏是一个常见且严重的问题,一旦发生,会导致程序运行效率下降,最终可能导致程序崩溃。本文将对C++中
    2023-10-22

    c#非托管内存的释放问题如何解决

    这篇“c#非托管内存的释放问题如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“c#非托管内存的释放问题如何解决”文章吧
    2023-07-05

    C#开发中如何处理内存分配和垃圾回收问题

    C#开发中如何处理内存分配和垃圾回收问题在C#开发中,内存分配和垃圾回收是非常重要的问题。合理处理内存分配和垃圾回收可以提高程序的性能和稳定性。本文将介绍一些处理内存分配和垃圾回收的常用技巧,并提供具体的代码示例。避免频繁的对象创建和销毁频
    2023-10-22

    C#路径问题中的如何保存问题的解决方法

    本篇内容主要讲解“C#路径问题中的如何保存问题的解决方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#路径问题中的如何保存问题的解决方法”吧!C#路径问题之保存路径的提问我在项目里建立了一个
    2023-06-18

    如何解决PHP开发中的内存溢出问题

    随着PHP的应用越来越广泛,PHP开发中的内存溢出问题也成为了开发者们共同面临的挑战。内存溢出是指程序在运行过程中申请的内存超过了内存空间的限制,导致程序出现异常或崩溃的情况。本文将介绍如何解决PHP开发中的内存溢出问题,并提供一些具体的代
    2023-10-21

    教你如何解决DPDK内存大页在NUMA架构重分配问题

    在DPDK中往往是在内核启动参数中设置要启动的大页的总数量,比如设置大页个数为16个,每个大页是1G,这样系统启动后,就能在/sys/devices/system/node/node0/hugepages/hugepages-1048576
    2023-06-05

    如何解决Go语言中的内存管理问题?

    如何解决Go语言中的内存管理问题?在Go语言中,内存管理是一个重要的话题。由于Go语言自带的垃圾回收器(Garbage Collector)的存在,开发者不需要手动管理内存分配和释放,但这并不意味着我们可以完全忽视内存管理的问题。不合理的内
    2023-10-22

    如何解决PHP开发中的内存泄漏问题

    导语:内存泄漏是指程序执行时无法释放已经分配的内存,导致内存占用不断增加,最终导致程序崩溃。在PHP开发中,内存泄漏是一个普遍存在的问题。本文将介绍如何解决PHP开发中的内存泄漏问题,并提供具体的代码示例。一、使用unset()函数手动释放
    2023-10-21

    C++ 函数调试详解:如何调试包含动态内存分配的函数中的问题?

    在 c++++ 中调试包含动态内存分配的函数时,可使用:调试器(gdb/lldb)检查内存分配/释放(valgrind)断言异常处理实战案例:函数 free_twice 错误:释放已释放内存使用 gdb 调试,发现断言失败检查变量值,确定问
    C++ 函数调试详解:如何调试包含动态内存分配的函数中的问题?
    2024-05-04

    如何解决Go语言中的并发内存泄漏问题?

    如何解决Go语言中的并发内存泄漏问题?引言:随着大数据和云计算时代的到来,对于并发编程的需求变得越来越迫切。而Go语言作为一门支持高并发的语言,受到了广泛的关注和应用。然而,并发编程不仅仅带来了高性能和高效率,同时也带来了一些风险,其中最常
    2023-10-22

    如何解决Go语言中的并发内存访问冲突问题?

    如何解决Go语言中的并发内存访问冲突问题?在Go语言中,我们可以使用goroutine来实现并发编程,这无疑给我们带来了更强大的性能和并行处理能力。然而,并发编程也会引发一些问题,其中最常见的就是内存访问冲突。内存访问冲突问题是指多个gor
    2023-10-22

    如何解决小程序开发中遇到的问题

    这篇文章主要介绍了如何解决小程序开发中遇到的问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。小程序面试题1. bindtap和catchtap的区别是什么?bind事件绑定
    2023-06-14

    如何解决定位并修复Go 中的内存泄露问题

    这篇文章将为大家详细讲解有关如何解决定位并修复Go 中的内存泄露问题,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Google Cloud Go 客户端库 [1] 通常在后台使用 gRPC 来连接 Goo
    2023-06-25

    编程开发中如何解决数值排序的问题

    这篇文章主要为大家展示了“编程开发中如何解决数值排序的问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“编程开发中如何解决数值排序的问题”这篇文章吧。出题目的: 掌握任意数列之间的排序技巧 解题
    2023-06-08

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录