微灯手握寸笔,细谈内存管理

目录

    • 传统艺能
    • 过渡区
    • 正片开始
    • 地址空间
    • 指针与内存关系
    • 内存分配与初始化细节
    • 内存泄漏
    • Cookie

传统艺能

小编是大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】
乔乔的gitee代码库(打灰人 )欢迎访问,点我!

过渡区

现在是北京时间14:00,期末考试,上午线代,还算顺利;天是灰色的今天超冷,听说成都的家好像下雪了还没问爸爸妈妈是不是真的,如果是真的希望回家的时候还能看见雪吧。
微灯手握寸笔,细谈内存管理_第1张图片

正片开始

地址空间

微灯手握寸笔,细谈内存管理_第2张图片

首先我们回味一下之前的老图,这个图由于是我手残加 ppt 即时创作,又因为是C语言入门时讲的,内容非常粗糙磕碜。要仔细研究这张图我们应该将它翻转90度会更加容易理解更贴近原理:
微灯手握寸笔,细谈内存管理_第3张图片

我们所熟知的,栈区数据存储的地址是从高地址到低地址,堆区数据存储的地址则是由低到高,而堆区下面可细分为未初始化和已初始化的全局数据区,字符常量区和代码区。而细心的你可能注意到了我代码区下面留了一撮空间代表下面还有,但这一撮属于灰色地带,目前看作为 “内存” ,但本质上不是内存,涉及到计算机操作系统原理不赘述。

从内存中0x000……0到堆区的地方其实基本上伴随整个程序的运行一直都存在,我们相对熟悉的就是栈区和堆区,栈区的我们函数调用后临时变量在栈帧中形成,随着申请与释放来进行空间管理。

那伴随整个程序的运行一直都存在的这部分数据,像 static 这类函数修饰的变量,为什么又会被改变生命周期呢?其实在编译的时候就被编译进了全局数据区。

指针与内存关系

void function(char *a)
{
  return 1;
}

我们在写函数时如果内容传的是指针,如果有好的习惯一般会先去对指针做一下合法性判定,这个判定什么意思,比如我们传了一个野指针,它会指向内存中任何一个位置,我是没有办法确认这个随机位置有无访问权限,所以要做合法性判定。

但是指针如果有具体的指向,对应的合法性我们是没办法验证的,包括野指针,是不是很疑惑,野指针不是随机指向,说白了就是乱指,那还没办法验证吗?是的,没办法。很简单,确认指针具体值的合法性,这不是咱作为用户可以做到的,这属于操作系统职责。
微灯手握寸笔,细谈内存管理_第4张图片

这种尴尬的情况我们所谓的合法性判定怎么搞呢?我们所谓的“合法”是落足于应用层面。其实所有的指针在没有被使用时,我们都应该设置成 NULL,这是一个规范问题。

在函数内部要验证指针合法性时,本质上就是在验证指针( !=NULL)。可以直接 if 判断,还有就是很多书中用的一个检查指针的宏——assert ,一般是在调试阶段使用,assert(name)如果内部条件不满足非空,就会直接咔嚓掉,中道崩殂没有后续。但是不好意思,assert只能检验是否 NULL,不能检验是否为野指针。

内存分配与初始化细节

之前就想专门提一下几个和内存空间有关联的函数,现在就放在这里一起总结了吧。

我们为指针分配了内存,但是内存大小多少会影响实际结果,不够就会造成越界。

char *p = "hello";
char *q = (char*)malloc(sizeof(char)*strlen(p)+1*sizeof(char));
strcpy(q,p);

微灯手握寸笔,细谈内存管理_第5张图片

p是字符串变量,长度为 5 个字符,但实际内存占用 6 个字符,不要忘了" \0 ",所以我们做 +1 处理,分配完了记得要初始化,初始化为非必须操作,但建议初始化,这是为了能让咱编码盘的明明白白。我们初始化变量时直接 0 或者 NULL,数组可以 = {0},也可以使用 memset 函数:

memset(a,0,sizeof(a));

它的 3 个参数分别代表起始地址,初始化设置的值以及设置的内存大小,单位为字节。

内存泄漏

int main()
{
while(1)
{
int *p = malloc(1024);
}
}

这里不做测试了,这会让电脑越来越卡,死循环加申请空间,程序级别的老赖,空间只借不还,以上代码就生动诠释了何为内存泄漏。

给个C语言之外的问题:程序挂了,已经退出了,那内存泄露问题还在吗?我自己的想法是在的,因为内存已经被申请了,退出程序只是终止了空间继续申请,不影响已产生的空间。但是我错了,其实在程序退出时,操作系统会强制拿回这部分空间,内存泄漏也就不在了。

所以诸位警惕windows的操作系统和杀毒软件这类常驻进程,几乎从来不会退出,最怕的就是内存泄漏,蓝屏安排,卡顿安排;但后端的服务器也是如此,无时无刻提供服务,一但内存泄露就会嘿嘿。

Cookie

malloc 之后空间要给 free 掉,我们 free(p)目前只知道堆空间的起始地址,并不知道要释放多少空间,如果 p 是 5 个字节,那么 free 一定会释放的比5个字节多,那么辩证思维,其实申请的空间就一定会比 5 个字节多。

编译器是怎么做到正确释放呢?其实实际 malloc 申请空间的时候,系统就会给的更多,多出来的部分,记录的就是申请的详细信息:空间大小,申请时间等等,free 会确认信息然后精准 free掉

这部分多申请的空间叫 cookie,内存级的 cookie,就是用来保存这些信息的。再延伸就是C语言的边界操作系统了,不赘述。

所以我们在 malloc 时肯定是申请大空间会更好,因为 cookie 的比例会更小,想象一下利息相同时你会借多借少就能体会了。

今天就到这里吧,摸了家人们。

你可能感兴趣的:(内存,C语言,操作系统)