我提出的一个小问题
让我们先看一个小问题,
观察下面代码,当malloc一块空间后,没有释放,这块空间会被泄露吗?
char * s = (char * )malloc(1024);
exit(0);
- 当这个进程不是一直运行的进程时,它不会被泄露,因为当这个进程结束后,该进程的空间都会被释放(假如说这个都会造成内存泄漏的话,那么操作系统的健壮性也太差了吧)
- 当该进程是一直运行的进程,如挂载在服务器上的 ,那么它将在运行中造成内存泄漏,直至把空间耗尽。
第一道题
这是32位的(内存只有2G)的rad hat 的内存图,而且现在已经有其他进程占用了一部分空间了
让我们运行这个代码,它将申请2G空间,大家猜猜能不能申请成功?
运行之后,查看内存状态,我们发现申请成功了
我们可以看出,当内存快到达2G时,有一部分内存被挤压到虚拟内存去了
第二道题
还是在上面的32位内存为2G的rad hat 上运行这个程序,当我们运行下面的代码时,此时我们要申请3G的空间,我们上次也看到,物理内存与虚拟内存之和为4G,远远大于3G,此时能不能成功?
当我们执行时,发现成功不了
那这个是为什么呐?
这个也和虚拟内存有关
简单介绍一下虚拟内存
Linux:
为了屏蔽I/O的差异,操作系统提供了虚拟文件系统(VFS)
为了屏蔽内存和I/O的差异,操作系统提供了虚拟存储器(虚拟内存)
为了屏蔽CPU 内存和I/O,也为了方便调动资源,操作系统提供了进程这一概念
为了安全性,同时为了使多进程环境下,使得进程之间的内存地址不受影响,于是
提供了虚拟内存中一概念
那虚拟内存的空间有多大呐?
虚拟内存大小和CPU的位数有关
CPU 在 ALU这个算数逻辑单元中运算数据
所以CPU 的位数指的是ALU的宽度,也就是数据总线的个数
CPU位数 | 数据总线 | 地址总线 |
---|---|---|
8位 | 8 | 16 |
16位 | 16 | 20 |
32位 | 32 | 32 |
n位CPU,虚拟空间的大小就为2^n次方。
对于上面的32位系统来说,虚拟空间的大小为4G。
32位系统虚拟内存分布图
在引入虚拟内存前,当一个程序想要运行时,它首先要能被加载在内存(内存的大小要足够)中
下面的图的物理内存的大小装不下这个程序,所以不能运行。
而当我们有了虚拟内存后,我们就可以把磁盘当作内存(虚拟成内存)来用,在运行程序时,把程序的一部分存储到内存中,一部分存储到磁盘中
而当我们需要使用页面4时,我们便从磁盘中把4加载到内存中,把好长时间没用的页面(比如说7)替换掉,把7放到磁盘中
因为对于32位系统来说,虚拟内存只有4G,而虚拟内存又分为内核区和用户区,内核区为1G,而用户区只为3G,所以当要malloc时,申请的空间必须小于3G,因为栈等其他东西也要占用内存。
所以当问分配空间够不够时?
我们不只能只关注内存,还要考虑到虚拟内存,而当考虑虚拟内存时,还要考虑到用户空间。
这样的话,我在学这里的时候突然有一个问题
根据上面我们所知的,只要我们的磁盘能把程序全部装载进去,不管内存多的大小,,当执行的时候,我们只需要从磁盘把程序全部加载到内存中去,这样的话,只要磁盘有多大,那么虚拟内存就可以有多大
但是我之后就想清楚了,因为内存,L1,L2,L3 ,三级缓存,这些东西,本来存在的目的就是为了减少CPU和磁盘速度的差异,如果说按我上面想的那样的话,这样内存存在的意义就没有了。
简单介绍一下malloc的过程
当我们不malloc时,堆那里啥空间都没有,当我们执行一次malloc时(要求分配字节比较小),然后会初始化堆(堆那里便会划分100多k的空间)然后,划分好字节块,比如说划分上好多个16个字节的,32个字节的,64个字节的,128个字节的,比如说你要60个字节的,就给你64个字节的块,当用户free之后,便会把字节块归还到这里(并不是归还给系统),然后说随着用户的使用,这里的字节块不够了,那么堆便继续扩展
假如说用户要划分1个G,那么便不从这里的空闲块区划分了,而是直接在堆区上划分1个G,然后给用户
我们来打个比方,假如说堆比作卖水的小卖部,假如学校里面一直没有人买水,小卖部这里肯定也没有屯水,因为没有这种需求,而有一天有一个人要提出买水,突然有了需求,小卖部这里就开始备几件水,当然肯定不能备好几十件吧,因为一直从来没有人买过水,而今天这种买水的需求是突然的,假如说有一天,学校要开运动会,有一个人突然要买一百件水,一到小卖部,发现不够呀,然后小卖部老师直接联系批发商,直接让批发商送给那个人。