C语言修行之基础篇(十四)管理内存:栈(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结束;
全局变量从整个程序一开始执行就开始,直到整个程序结束才会消灭。

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bazinga bingo

您的鼓励就是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值