0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是堆内存?堆内存是如何分配的?

电子工程师 来源:单片机匠人 作者:蔡琰老师 2021-07-05 17:58 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

上一篇我们分享了栈内存的概念,现在我们分享下堆内存的概念。

在一般的编译系统中,堆内存的分配方向和栈内存是相反的。当栈内存从高地址向低地址增长的时候,堆内存从低地址向高地址分配。

C语言中,堆内存在分配和释放的时候,是程序通过调用C语言的库函数完成的。这和栈内存的分配有区别,栈内存利用的是处理器的硬件机制,而堆内存的处理使用的是库函数。

我们来看下堆内存的分配情况:

在堆内存的分配过程中,每次分配将返回一个当前分配地址的指针。在程序中如果多次分配内存,可以得到多个内存指针,每个内存指针都是本次分配内存的地址。在释放内存的时候,只需要对每个指针进行操作,那个指针所指向的内存就会被释放,而对其他的内存区域没有影响。

从内存的分配和使用上,可以看出栈内存和堆内存的区别:栈内存只有一个入口点,就是栈指针,栈内存压入和弹出的时候栈指针将发生变化,栈指针标识当前栈区域中已使用和未使用的界限,程序在访问栈内存的时候都只能通过栈指针及其偏移量;而堆内存有多个入口点,每次分配得到的指针是访问内存的入口,每个分配内存区域都可以被单独释放,程序对堆内存可以通过每次分配得到的指针访问。

堆内存有一个整体分配的过程,按照向上的堆内存分配方向。随着堆内存使用量的增加,堆内存将逐渐向高地址分配。这只是一个大体的增长的方面,在堆内存中,已使用的区域和未使用的区域是交错的,而不是像栈区域那样有明显的分界线。

堆内存的释放看下面这个图:

看到这样频繁的使用区域和释放,那么很容易看出堆内存是不连续的,跟堆内存的使用方式有关系,这个分配就相对自由灵活了,但是也是会在低地址向高地址发展的方向分配的。

比如上面释放后再分配就可以是下面两种情况:

先看再次分配1的情况:当新分配的需求比中间(刚刚释放)区域小,那么就会在紧接着的区域给分配。

再看再次分配2的情况:当新分配的需求比中间(释放的)区域大,那么只能往后寻求能给的区域。

当频繁的分配和释放内存的过程中,会很容易出现在两块已经分配的内存之间较小的未分配内存区域,这些其实可以用,但是由于他们的空间比较小,不够连续内存的分配,所以分配的时候就很难再次使用,这些较小的内存就是我们常说的内存碎片。

我们再来聊一下在C程序中堆空间的使用。

在C语言中,堆内存区域的分配和释放是通过调用库函数来完成的,实现的函数主要有四个:

void *malloc(size_t size); //分配内存空间

void free(void *ptr); //释放内存空间

void *calloc(size_t nmemb,size_t size); //分配内存空间

void *realloc(void * ptr,size_t size); //重新分配内存空间

注意:使用上面这几个函数需要包含标准库文件

那么库函数怎么使用呢,内存分配了就要有释放,那么常用的就是malloc()和free()两个函数。malloc()函数的输入是需要分配内存的大小,输出是分配内存的指针。如果分配不成功,则返回NULL。

free()函数的输入是需要释放的指针,可以接受任何形式的指针。这个指针必须是由分配函数分配出来的。

例如:

int *pa;

pa = (int *)malloc(sizeof(int));//分配一个int大小的指针

if(NULL != pa)

{

free(pa);

}

内存使用完成需要释放,以便分配给其他程序使用。

calloc()也是内存分配的,只是可以把分配好的内存区域的初始值全部设置为0。还有这个分配内存有两个参数,第一个是分配单元的大小,第二个是要分配的数目。

malloc(sizeof(unsigned int)*10); == calloc(sizeof(unsigned int),10)

realloc()有两个参数,一个是指向内存的地址指针,一个是要重分配内存的大小,返回值是指向所分配内存的指针。

1、当参数指针为NULL的时候,作为malloc使用,分配内存。

2、当重分配内存大小为0的时候,作为free使用,释放内存。

3、当指针和重分配内存大小均不为0的时候,根据指针指向的堆内存区域的情况和指针大小重新分配内存。

对于realloc()作为重新分配内存的时候,有三种可能出现:

1、缩小内存

2、扩大内存,不需要移动指针

3、扩大内存,需要移动指针(指定内存区域大小不够)

在堆内存的管理上,主要容易出现以下几个问题:

1、开辟的内存没有释放,造成内存泄漏(系统不会释放任何用户分配的内存)

2、野指针被使用或释放(内存释放后,需要将内存指针置为NULL)

3、非法释放指针(分配了有效内存才存在释放,否则是非法的)

在C语言语法的方面对栈内存和堆内存如何使用没有限制。然后从使用的角度,栈内存更适用于容量较小的单个变量(例如:C语言的基本变量类型、较小的结构体和数组),堆内存则适用于开辟较大块的内存。栈内存由编译器分配和释放,堆内存由程序员分配和释放。

责任编辑:lq6

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内存
    +关注

    关注

    9

    文章

    3234

    浏览量

    76518
  • C语言
    +关注

    关注

    183

    文章

    7646

    浏览量

    146172

原文标题:堆内存的那些事

文章出处:【微信号:gh_e7f294a514ca,微信公众号:单片机匠人】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    LuatOS的内存分配机制

    不同 LuatOS 硬件平台在内存布局上存在差异,Lua 运行内存、系统内存与 PSRAM 扩展内存分配方式各有区别。部分型号将系统与脚本
    的头像 发表于 04-16 12:37 115次阅读
    LuatOS的<b class='flag-5'>内存</b><b class='flag-5'>分配</b>机制

    DDR5内存断崖式下跌或引发踩踏式抛货?

    内存
    芯广场
    发布于 :2026年03月30日 15:35:23

    MangoTree Halo Ultra「全新PXI」,标配自动纠错内存#

    内存
    芒果树数字
    发布于 :2026年03月06日 15:59:34

    curl中的TFTP实现:整数下溢导致内存越界读取漏洞

    可能已经超过了已分配的缓冲区大小。紧接着的第12行 sendto 调用就可能发送超出缓冲区边界的数据。 1 2 3 4 5 6 7 8 9 10 影响 此漏洞的潜在影响是信息泄露,即可能将内存中的内容
    发表于 02-19 13:55

    keil中c语言的动态分配内存

    于处理器的指令集中,效率很高,但是分配内存容量有限。另外,当函数运行结束时,栈区的空间会被自动释放。 (3)内存映射段。该部分内存主要用于文件映射、动态库以及匿名映射。 (4)
    发表于 01-21 06:04

    【「Linux 设备驱动开发(第 2 版)」阅读体验】+读深入理解Linux内核内存分配

    每个内存地址是虚拟的,不是直接指向RAM中的任何地址。当用户访问内存中的存储单元时,都会进行地址转换以匹配相应的物理内存。书籍的第10章讨论了五个主题,对Linux内核内存
    发表于 01-16 20:05

    内存持续涨价,多重信号预警成本压力#内存芯片#涨价#行业#消费电子#AI#

    内存芯片
    jf_15747056
    发布于 :2026年01月08日 18:38:35

    嵌入式系统中,动态分配内存可能发生的问题是什么?

    尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从(heap)中动态分配内存的过程的。 那么嵌入式系统中,动态分配内存可能发生的问题是什
    发表于 12-22 09:42

    三种类型内存的使用

    给上级调用函数。通常被称为“”。 静态存储:在程序的整个生命周期内有效。在进程启动时分配,全局变量都存储在这里。 如果想通过一个函数“返回”内存,不必通过调用 malloc,可以直接将一个指向
    发表于 12-12 06:43

    使用Keil MicroLIB时自动设置大小

    项目的过程中,市场遇到各种各样问题,栈穿透到里面,或者不够大,相当烦人! 有时候就在想,何不让全局变量以外的所有RAM给堆栈共用? 因为从低到高分配,而栈从高到低
    发表于 12-09 07:04

    和栈的区别

    一个由C/C 编译的程序占用的内存分为以下几个部分: 栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 区(heap):一般由
    的头像 发表于 11-27 18:13 1237次阅读

    如何在应用程序调试期间分析栈和使用情况

    随着 AMD Vitis 统一软件平台 2021.2 的发布,Vitis 引入了一个 Tcl 脚本,用于在应用程序运行的特定时间点协助查找栈和内存使用情况。该脚本已延续到后续的 Vitis 版本
    的头像 发表于 10-24 16:54 1048次阅读
    如何在应用程序调试期间分析栈和<b class='flag-5'>堆</b>使用情况

    WebGL/Canvas 内存泄露分析

    的 JavaScript 对象未释放要复杂得多。一个现代 WebGL/Canvas 应用的内存版图实际上跨越了三个截然不同但又相互关联的内存区域: 图 V8 引擎管理的 JavaScript (JS Heap
    的头像 发表于 10-21 11:40 545次阅读
    WebGL/Canvas <b class='flag-5'>内存</b>泄露分析

    stm32cubeIDE使用malloc失败是什么原因?

    我在stm32cubeIDE环境下,已经分配了足够的栈与空间,但是我在的使用malloc分配内存时,一直分配不成功,这是什么原因?
    发表于 06-09 07:24

    stm32cubeIDE使用malloc失败是什么原因?

    我在stm32cubeIDE环境下,已经分配了足够的栈与空间,但是我在的使用malloc分配内存时,一直分配不成功,这是什么原因?
    发表于 06-04 07:18