内存的秘密


前言

内存是外存与CPU进行沟通的桥梁,包括随机存储器(RAM),只读存储器(ROM),以及高速缓存(CACHE)。
文章简单讲讲内存分配器相关的知识。


一、内存分配器

1.内存块

内存块中,可以装入原生的字节序列,申请者拿到该内存块后可以塑造成整数、浮点数、链表、二叉树等数据结构以及对象、结构体等,这是使用者的事情,同时,我们将维护内存块的分配信息保存在内存块本身中

2.内存分配信息

内存块中取4字节,也就是32比特位中,31个比特位来记录块大小,剩下的一个比特位f/a(free/allocate)用来标识该内存块是否空闲,同时增加一个信息尾,方便释放内存时,可以快速的进行相邻空闲内存块的合并。
在这里插入图片描述

二、内存池

1.malloc

(C/C++)申请内存使用的是malloc。
在这里插入图片描述

2.内存池技术

内存池技术一次性获取到大块内存,然后在其之上自己管理内存的申请和释放,这样就绕过了标准库以及操作系统。
在这里插入图片描述

3.线程局部存储(__thread关键词修饰)

线程局部存储技术,每个线程维护一个内存池。
全局变量在每个线程中都有自己的副本,变量指向的值是线程私有的。
假设这个全局变量是一个整数,变量名字为global_value,初始值为100,那么当线程A将global_value修改为200时,线程B看到的global_value的值依然为100,只有线程A看到的global_value为200,这就是线程局部存储的作用。

三.内存四区

内存四区,分为栈区,堆区,代码区,数据区

  • 栈区
    栈区由系统自动分配内存,用于存放函数参数,局部变量等,离开作用域自动释放。当函数A调用函数B时,函数B的“第一条”机器指令在A的寄存器里。
  • 堆区(heap)
    内存动态申请和释放都发生在堆区。
    堆区内存由程序员通过new和free关键字主动申请和删除,堆区申请内存需要查找堆区中记录空闲内存地址的链表,遍历该链表找可以放下所需空间大小的内存,并进行记录。
  • 代码区
    存放函数体内的二进制代码,由操作系统管理,共享,只读
  • 全局区
    存放全局变量,静态变量以及常量。

四.内存泄漏

以C语言为例:

void memory_leak()
{
	int *p = (int *)malloc(sizeof(int));
	return;
}

上述代码在申请一段内存后直接返回,这样申请到的这块内存在代码中再也没有机会释放掉了,这就是内存泄漏。

五.CPU的寄存,是怎么装入内存的结构体的?

  • Load/Store指令
    在精简指令集架构下,会有特定的机器指令,Load/Store指令,来读写内存。

代码:

sum += huge_arr[100];

得到机器指令:

load $r0 100($r2)//加载到寄存器r0中
add $r1 $r1 $r0

第一行指令,数组首地址存放在寄存器r2中,100($r2)表示数组首地址+100,这样我们就能得到huge_arr[100]的地址了,然后将该地址中的值利用load指令加载到寄存器r0中。
第二行指令,r1寄存器中保存的是sum的值,该行指令执行过后r1中的值就已经加上了huge_arr[100]。
编译器把那些经常使用的数据放到寄存器,剩下的放到内存中,然后利用内存读写指令(Load/Store)在寄存器和内存之间来回搬运数据。

六.C语言中的指针

当一个变量不仅仅可以用来保存数值,也可以保存内存地址时,指针诞生了。比如b不需要存a的N个字节,只需要存a在内存中的地址。

举例:

store $1 6

数字1前面加上$符号的就表示数值,否则就是地址。
“@”可以将数值解释为内存地址,例如以下的间接寻址:

load r1 @1

这时该指令会首先把内存地址1中保存的值读取出来发现是3,然后再次把3按照内存地址进行解释,3指向的数据就是变成了a:
地址1 -> 地址3 -> 数据a。
指针是内存地址的更高一级抽象。

  • 指针这个概念首次出现在 PL/I 语言中,当时是为了增加链表处理能力。

  • debug
    指针指向不存在的变量:

int fun(){
	int a = 2;
	return &a;
}
void main(){
	int *p = fun();
	*p = 20;
}

局部变量 a 位于 func 的栈帧中,当 func 执行结束,其栈帧也不复存在,因此 main 函数中调用 func 函数后得到的指针指向一个不存在的变量。

a = &b; 语句就是将b的存储单元的地址存入a存储单元中。
C语言规定*a代表a中存储的地址对应的存储单元中的数据,也就是访问*a就等于访问b,于是*a提供了通过a访问b中的数据的手段。


总结

了解到内存相关的概念后,下一章讲讲进程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值