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

简介: 正片开始👀地址空间👏

image.png

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

image.png

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


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


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


指针与内存关系👏

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

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


但是指针如果有具体的指向,对应的合法性我们是没办法验证的,包括野指针,是不是很疑惑,野指针不是随机指向,说白了就是乱指,那还没办法验证吗?是的,没办法。很简单,确认指针具体值的合法性,这不是咱作为用户可以做到的,这属于操作系统职责。

这种尴尬的情况我们所谓的合法性判定怎么搞呢?我们所谓的“合法”是落足于应用层面。其实所有的指针在没有被使用时,我们都应该设置成 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);

image.png

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 的比例会更小,想象一下利息相同时你会借多借少就能体会了

相关文章
|
4天前
|
存储 开发框架 .NET
"揭秘.NET内存奥秘:从CIL深处窥探值类型与引用类型的生死较量,一场关于速度与空间的激情大戏!"
【8月更文挑战第16天】在.NET框架中,通过CIL(公共中间语言)可以深入了解值类型与引用类型的内存分配机制。值类型如`int`和`double`直接在方法调用堆栈上分配,访问迅速,生命周期随栈帧销毁而结束。引用类型如`string`在托管堆上分配,堆栈上仅存储引用,CLR负责垃圾回收,确保高效且自动化的内存管理。
19 6
|
2月前
|
存储 C语言 C++
【C++航海王:追寻罗杰的编程之路】C&C++内存管理你知道哪些?
【C++航海王:追寻罗杰的编程之路】C&C++内存管理你知道哪些?
14 0
|
3月前
|
存储 安全 程序员
探秘C/C++动态内存分配:从必要性到经典问题剖析
探秘C/C++动态内存分配:从必要性到经典问题剖析
163 0
|
存储 算法 程序员
拟内存管理技术
拟内存管理技术
86 0
|
8月前
|
存储 算法 JavaScript
牛皮了!世界级调优大师以上古传承之魔法,彻底揭开GC的秘密
计算机的进步,特别是硬件的发展之快总是让我们感到惊讶。在这波不断向前涌动的洪流中,技术领域的浮沉也愈发激烈。本书涉及的垃圾回收(Garbage Collection, GC)与其说是理论,其实更偏向技术层面,然而它却有着令人吃惊的漫长历史。GC在计算机发展的激流中没有浮起,也没有沉下。直到1995年Java发布,因为其内藏GC,人们才开始意识到GC的作用。
|
存储 Java
java内存机制详解,老年人也看得懂
java内存机制详解,老年人也看得懂
65 0
满地坑!细数IO操作的几个坑
IO是我们日常开发中经常使用到的技能,但是一不小心我们就会踩坑,今天梳理了我在工作中遇到的一些问题
并发程序设计,你真的懂吗?
并发程序设计,你真的懂吗?
86 0
并发程序设计,你真的懂吗?
|
SQL JavaScript 前端开发
#你会担心掌握的技术语言过时吗?#一入编程深似海,从此妹子是路人
我掌握的技术语言有C、C++、ActionScript、JavaScript、TypeScript、Flex、Java、SQL、Scala、CAD,当然,这还不算一些具有特殊语言的技术框架,如Vue.js、Angular、Spark、Android、HarmonyOS、Node.js等,如果算上就更多了。
241 0
|
存储 缓存 Linux
真棒! 20 张图揭开内存管理的迷雾,瞬间豁然开朗
本篇跟大家说说内存管理,内存管理还是比较重要的一个环节,理解了它,至少对整个操作系统的工作会有一个初步的轮廓,这也难怪面试的时候常问内存管理。
真棒! 20 张图揭开内存管理的迷雾,瞬间豁然开朗

相关实验场景

更多