内存管理--学习笔记


C语言进程的内存布局:

程序:就是我们写好的代码并编译完成的那个二进制文件,它被存放与磁盘(硬盘)中,它是死的。

进程:把磁盘中的二进制文件"拷贝"到内存(内存条)中取执行它,让运行起来,它是活的。

所有的程序被执行起来之后,系统会为他分配各种资源内存,用来存放该进程中用到的各种变量、常量、代码等等。这些不容的内容将会被存放到内存中不同的位置 (区域),不同的内存区域他的特性是有差别。

每一个进程所拥有的内存都是一个虚拟的内存,所谓的虚拟内存是用物理内存中映射(投影)而来的,对于每一个进程而言所有的虚拟内存布局都是一样的。让每个进程都以为自己独自拥有了完整的内存空间

物理内存(Physical Memory)

虚拟内存(Virtual Memory)

img

虚拟内存的布局(区域):

栈 (stack)

堆(heap)

数据段

代码段

img

img

栈空间

img

栈空间的特点:

  • ​ 空间非常有限,尤其在嵌入式的环境下,因此我们应该尽可能少去使用栈空间内存,特别是要存放比较大的数据。

ulimit -a

stack size (kbytes, -s) 8192 当前64位系统 默认只有8M栈内存

$ ulimit -s 10240 // 临时修改为 10M 重启后会回到默认值

  • ​ 每当一个函数被调用的时候, 栈空间会向下增长一段,用来存放该函数的局部变量
  • ​ 当一个函数退出的时候 , 栈空间会向上回缩一段,该空间的所有权将归还系统
  • ​ 栈空间的分配与释放,用户是无法干预的, 全部由系统来完成。
  • 先进后出

静态变量

在C语言中有两种静态变量

​ 全局变量: 定义在函数体之外的变量

​ 静态的局部变量: 定义在函数体内部而且被 static 修饰的变量

int c ;   // 在函数体之外,属于全局变量 --> 静态变量

int  func(int argc , char * argv[] )  // argc argv 属于main函数的局部变量
{
    int a ;   // 局部变量
    static int b ;  // 静态局部变量
    //  静态的局部变量 初始化语句只会被被执行一次
        
}

为什么会有静态变量?

  • 当我们需要把一个变量引用到不同的函数内部甚至不在同一个.c 文件中,可以全局变量来实现。
  • 当我们需要一个局部变量用来记录某个值, 并希望这个值不会被重新初始化的情况下可以使用静态的局部变量。(static 修饰)

数据段与代码段

数据段有哪些内容:

  • ​ .bss 未初始化的静态数据 , 会被自动初始化为0
  • ​ .data 已初始化的静态数据
  • ​ .rodata 存放常量数据 “Hello Myoung” , 不允许修改的(只读)

代码段中有那些内容:

  • 用户的代码 (比如我们自己写函数func…main)
  • 系统初始化代码,由编译器为我们添加的

img

img

堆内存

堆内存,又称为动态内存、自由内存、简称堆。唯一一个由开发者随意分配与释放的内存空间。具体的申请大小,使用的时常都是由我们自己来决定。

堆内存空间的基本特性:

  • ​ 相对与栈空间来说 ,堆空间大很多(堆的大小受限于物理内存),系统不会对对空间进行限制。
  • ​ 相对与栈空间来说, 堆内存是从下往上增长的。
  • ​ 堆空间的内存称为匿名内存, 不像栈空间那样有个名字,只能通过指针来访问
  • ​ 堆空间内存的申请与释放都是由用户自己完成,用户申请之后需要手动去释放,直到程序退出。

如何申请堆空间内存:

malloc (只是申请内存而已,并不会/清空)

malloc (向系统申请内存)

头文件: #include <stdlib.h>

函数原型: void *malloc(size_t size);

参数分析: size --> 需要申请的内存 (字节为单位)

返回值: 成功 返回一个指向成功申请到内存的指针(入口地址) 失败 返回 NULL

calloc (会把内存进行清空)

calloc (向系统申请内存)

头文件: #include <stdlib.h>

函数原型: void *calloc(size_t nmemb, size_t size);

参数分析: nmemb – > N 块内存(连续的) size – > 每一块内存的大小尺寸

返回值: 成功 返回一个指向成功申请到内存的指针(入口地址) 失败 返回 NULL

realloc

realloc (重新申请空间)

头文件: #include <stdlib.h>

函数原型: void *realloc(void *ptr, size_t size);

参数分析: ptr --> 需要 扩容/缩小 的内存的入口地址 size --> 目前需要的大小

返回值: 成功 返回修改后的地址 失败 NULL

清空内存的值

​ 包含头文件<string.h>

bzero

​ 函数原型:extern void bzero(void *s, int n)

​ 参数分析:

​ 功 能: 置字节字符串s的前n个字节为零且包括‘\0’

memset

​ 函数原型:extern void *memset(void *buffer, int c, int count)

​ 功 能:把buffer所指内存区域的前count个字节设置成c的值。

bzero和memset区别

1、bzero()不是ANSI C函数,其起源于早期的Berkeley网络编程代码,但是几乎所有支持套接字API的厂商都提供该函数;

2、memset()为ANSI C函数,更常规、用途更广。(建议使用)

如何释放堆空间内存:

free

free(释放堆内存)

头文件: #include <stdlib.h>

函数原型: void free(void *ptr);

参数分析: ptr --> 需要释放的内存的入口地址

返回值; 无

内存拷贝函数:

memcpy

strcpy

strncpy

sprontf

总结

  • 使用malloc 申请内存时 , 内存中的值时随机值 , 可以使用memset清空
  • calloc 申请内存时 , 内存中的值会被初始化为 0
  • free 只能释放堆空间的内存,不能释放其它区域的内存
    释放内存的含义:
    1.释放内存仅仅意为着,当前内存的所有权交回给系统
    2.释放内存并不会清空内存的内容
    3.也不会改变指针的指向,需要手动把指针指向NULL ,不然就成野指针了
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Myoung_ss

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值