• C语言基础篇 —— 4.1 管理内存:栈(stack)、堆(heap)、数据区(.data)



    程序中的内存从哪里来?

    1、程序执行需要内存支持。 程序是放在内存中运行,程序运行时需要内存来存储一些临时变量。
    2、内存本身在物理上是一个硬件器件,由硬件系统提供。
    3、内存是由操作系统统一管理。 为了内存管理方便又合理,操作系统提供了多种机制来让应用程序使用内存。根据自己的使用情况来选择某种方式获取内存、使用内存、释放内存。


    操作系统管理内存方式

    操作系统用三种方法来管理内存: 栈(stack)、堆(heap)、数据区(.data)

    栈(stack)解析

    1、栈是在运行时自动分配和自动收回:栈是自动管理的、程序员不需要手工干预。
    2、反复使用:栈内存在程序中其实就是一块空间,程序反复使用这一块空间。
    栈是哪来的?—— 应用程序在操作系统中运行时,操作系统分配一块栈空间给应用程序使用。栈大小由操作系统决定的。栈指针是由操作系统控制 )
    3、脏内存:由于栈是反复使用的,每次使用后程序不会清理,因此分配到时保留原来的值
    4、临时性:变量在栈上只是临时分配了一个内存空间使用
    5、栈会溢出:操作系统分配的栈大小是有限的。大量使用栈会造成栈溢出。

    由于栈有以上几个特性,程序员中应注意几点:

    • 程序中定义局部变量的时候必须初始化。否则会出现莫名错误。
    • 函数不能返回栈变量的指针,因为这个空间是临时的。
    • 定义局部变量不能太大,避免栈溢出。

    堆(heap)解析

    1、操作系统堆管理器管理:堆管理器是操作系统的一块模块,堆管理内存分配灵活,按需分配。
    2、大块内存:堆内存管理者总量很大的操作系统内存块,各程序按需向操作系统去申请,使用完之后要释放。
    3、程序手动申请和释放:需要程序员写代码去申请malloc和释放free。
    4、脏内存:堆内存也是反复使用的,使用者用完释放前不会清除。
    5、临时性:堆内存只有在malloc和free之间属于这个进程,可以访问。

    整个使用堆内存程序流程:
    1、malloc申请内存并绑定(比如p) 2、判断申请是否成功 3、使用内存 4、释放内存

    malloc函数 返回的是一个void *类型的指针,实质上malloc返回是堆管理分配给我本次申请的那段内存空间的首地址(其实上就是一个数字,这个数字表示一个内存地址)。
    为什么是void * ? 主要原因是malloc帮我们分配内存时只是分配了空间,至于这段空间将来用来存储什么类型malloc是不关心的,后面由程序员来定。
    什么是void类型? void表示万能类型。void意思就是说这个数据类型当前不确定,在需要的时候可以再去指定它具体的类型。

    由于堆有以上几个特性,程序员中应注意几点:

    • malloc申请的内存时用完后要free释放。 free(p);会告诉对管理器这段内存我用完了可以回收了。堆管理器回收了这段内存后这段内存当前进程就不应该再使用。因为释放后堆管理器就可能把这段内存再次分配给别的进程。
    • 调用free归还这段内存之前,指向这段内存的指针p一定不能丢。 因为p一旦丢失这段malloc来的内存就永远的丢失了(系统泄露),直到当前程序结束时操作系统才会回收这段内存。
    • gcc中的malloc默认最小以16B分配单位的。 如果malloc小于16B的大小时都会返回一个16字节的大小内存。所以在你申请malloc(0)和malloc(4),堆管理器都分配16字节空间。

    数据区(.data)解析

    编译器在编译程序的时候,将程序中的所有的元素分成了一些组成部分,各部分构成一个段,所以段是可执行程序的组成部分。
    代码段 :代码段就是程序中的可执行部分,也可以理解代码段就是函数堆叠组成的
    数据段:程序中的数据,也可以理解为C语言程序中的全局变量。
    ( 注:全局变量才是程序的数据,局部变量不算程序的数据,只能算是函数的数据 )
    bss段:被初始化为0的数据段。

    数据段和bss段异同点
    数据段和bss段本质上没有区别,都是用来存放C程序中的全局变量。
    区别在于把显示初始化为非零的全局变量存在数据段(.data)段中,而把显示初始化为0或者没有显示初始化的全局变量存在bss段。

    有些特殊的数据会放到代码段
    1、C语言中使用char *p=“linux”;
    定义字符串,这个字符串不会被放在数据段,而是会被分配为代码段。这个字符串属于常量字符串而不是变量字符串。
    2、const型常量,C语言中const关键字用来定义常量,常量就是不能被改变的量。
    const类型实现方法:单片机的编译器编译将const修饰的变量放在代码段去实现不能修改
                                      gcc编译器是用来检查const类型的常量不会被修改,实际上const型的常量还是和普通变量一样放在数据段的。

    显示初始化为非零的全局变量和静态局部变量放在数据段
    放在.data数据段的变量有两种:
    1、显示初始化为非零的全局变量。
    2、静态局部变量,就是static修饰的局部变量。(普通局部变量分配在栈上,静态局部变量分配在.data段)

    未初始化或显示初始化为0的全局变量放在bss段
    bss段和.data段没有本质区别,几乎可以不用明确去区分这两种。


    总结

    C语言中所有变量和常量所使用的内存只有三种情况
    1、相同点:三种获取内存的方法,都可以给程序提供可用内存,都可以用来定义变量给程序用。
    2、不同点:栈内存对应C语言中的普通局部变量;堆内存完全是独立于我们的程序存在和管理的;数据段对于程序来说对应C程序中的全局变量和静态局部变量,函数内部临时使用,出了函数不会用到,就定义局部变量

    堆内存和数据段几乎拥有完全相同的属性,大部分时候是可以完成替换的。但是生命周期不一样。
    堆内存的生命周期从malloc开始到free结束;
    全局变量从整个程序一开始执行就开始,直到整个程序结束才会消灭。

  • 相关阅读:
    9月13日扒面经
    数据的备份和恢复
    Spring boot定时任务
    ADSP-21489的图形化编程详解(7:延时、增益、分频、反馈、响度)
    项目搭建(七)爱心代码❤网站部署(静态网站)
    项目经验分享:基于昇思MindSpore,使用DFCNN和CTC损失函数的声学模型实现
    CSS 滚动驱动动画 scroll-timeline ( scroll-timeline-name ❤️ scroll-timeline-axis )
    区块链是如何实现与现实相连接的?
    chmod,rwx Linux文件属性笔记221107
    什么是PaaS平台?
  • 原文地址:https://blog.csdn.net/weixin_43564241/article/details/127830981