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

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

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

相关文章
|
7月前
|
存储 程序员 C语言
【动态内存管理助力程序优化与性能飞升】(下)
【动态内存管理助力程序优化与性能飞升】
100 1
|
7月前
|
C语言
【动态内存管理助力程序优化与性能飞升】(中)
【动态内存管理助力程序优化与性能飞升】
|
7月前
|
存储 缓存 Java
金石原创 |【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系机制(1)
金石原创 |【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系机制(1)
88 1
|
4月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
115 1
|
2月前
|
存储 C语言 C++
【C/C++内存管理】——我与C++的不解之缘(六)
【C/C++内存管理】——我与C++的不解之缘(六)
|
4月前
|
Java UED 开发者
揭开Java性能提升之谜:异步编程如何让你的应用响应速度飞升?
【8月更文挑战第30天】随着互联网技术的发展,系统性能和用户体验成为关注焦点,异步编程因其能提高应用响应速度和吞吐量而在Java领域广泛应用。本文将详细阐述Java异步编程的概念与优势,并通过实战示例展示其在实际项目中的应用,如使用`Future`、`Callable`及`CompletableFuture`等接口和类实现异步操作,帮助开发者更好地理解和运用这一技术,以提升程序性能和用户体验。
43 0
|
6月前
|
存储 C语言 C++
【C++航海王:追寻罗杰的编程之路】C&C++内存管理你知道哪些?
【C++航海王:追寻罗杰的编程之路】C&C++内存管理你知道哪些?
29 0
|
7月前
|
存储 Linux 程序员
【操作系统原理】—— Linux内存管理
【操作系统原理】—— Linux内存管理
|
存储 算法 程序员
拟内存管理技术
拟内存管理技术
110 0
|
7月前
|
存储 安全 程序员
探秘C/C++动态内存分配:从必要性到经典问题剖析
探秘C/C++动态内存分配:从必要性到经典问题剖析
309 0

热门文章

最新文章