497-nginx内存池(小块内存分配)

我们回顾一下nginx内存池的结构体

在这里插入图片描述
create_pool开辟指定大小的内存块。都是一块一块分配的。每个内存池都有一个头,第一个内存块的头部信息比较详细。
同一个颜色表示同一个变量的里面的具体内容。

last指向的是可用内存的起始地址
end指向的是可用内存的末尾地址
current指向的是现在内存的起始地址,表示现在这个内存块是可以分配内存的
在这里插入图片描述
向内存池申请内存在nginx里有3个函数:
在这里插入图片描述
在这里插入图片描述
上面2个函数的区别是传入的参数,最上面那个考虑内存对齐,上面那个不考虑内存对齐

还有一个内存申请函数:
在这里插入图片描述
这个函数在内存开辟完之后,会给内存清0

剖析ngx_palloc

如何从nginx内存池申请内存???
在这里插入图片描述
传入的参数是内存池的起始地址,想向申请申请的内存的字节数
如果申请的内存字节数<=pool->max,就调用小块内存申请函数。
否则调用大块内存申请函数。
在这里插入图片描述
max是小块内存的上限。
max不可能超过1个页面的。
就是这块大小size,整个内存大小减去内存头

如果这白色块的大小小于一个页面,max记录的就是这块申请的大小,如果白色块的大小大于一个页面,max不可能超过1个页面的大小。
在这里插入图片描述
size如果小于等于max,就进入小块内存分配的函数
在这里插入图片描述

小块内存分配函数分析

在这里插入图片描述
current指向的是哪个内存池,就从哪个内存池开始分配,current赋值给p指针
在这里插入图片描述
然后进行do while循环
m指向可分配内存的起始地址

在这里插入图片描述
如果align为1,就是考虑内存对齐。
在这里插入图片描述
把m指针调整成平台相关的unsigned long的整数倍(调整到4字节或者8字节的整数倍)。
在这里插入图片描述
看第2个if语句:
在这里插入图片描述

然后下面的白色块大小如果大于等于size的话,这块白色内存最大的就是max,如果超过1个页面,size只能是一个页面的大小。内存池空闲的内存空间是大于等于申请的内存空间,当然就可以分配了。

在这里插入图片描述
然后把m指针偏移size个字节。
在这里插入图片描述
相当于在内存池给应用程序分配内存了。
在这里插入图片描述
然后return m了(m的位置没有改变,代表是分配内存的起始地址)
在这里插入图片描述

我们再来看另外1种情况

在这里插入图片描述

现在开始分配内存,如果end-m是10字节,但是size是需要分配20字节,也就是说,在这个内存池里面不够分配了。就不进入if语句执行了。然后执行下面这句
在这里插入图片描述

但是现在只有这1块内存块。p->next在刚开始初始化的时候是空。
所以p为空,就退出while循环了。
在这里插入图片描述
内存没有分配成功,就直接进入下面的函数,再去开辟内存块:
在这里插入图片描述
我们进入到这个函数里面:
在这里插入图片描述
我们一句一句看:
在这里插入图片描述

在这里插入图片描述
开辟和我们之前开辟的内存块一样大小的内存块,所以是用end-pool
然后开始开辟了
在这里插入图片描述
上面的黄色字是宏,如果没有特定平台的宏,调用的就是malloc,返回值给m
在这里插入图片描述
然后执行:
在这里插入图片描述
如图所示:
在这里插入图片描述
然后执行
在这里插入图片描述
下面的这些信息只需要存储在开辟的第一个内存块就可以了,后面开辟的内存块不需要这些信息,只需要存储管理当前内存块内存分配的4个指针项就可以了。
在这里插入图片描述
分配size大小内存:
在这里插入图片描述
每一个内存块都有last和end指向空闲内存空间的起始地址和末尾地址
然后执行for循环:

在这里插入图片描述
p=pool->current指向的是开辟的第一个内存块
在这里插入图片描述
如果p->d.next不为空。
然后判断:

在这里插入图片描述
刚开始,failed初始化是0,0+1=1,小于4,如果是大于4,会怎么样?
在这里插入图片描述
现在刚开始,就只申请了2个内存块
for循环是进不去的,因为p->d.next直接为空了,for循环直接跳出去了。
执行

在这里插入图片描述
把这2个内存块给连接起来了!
在这里插入图片描述
选择假设后边还有内存块分配的话,比如说再申请个11字节的内存块。
它都是从第一个开辟的内存块(current指针)开始判断,
在这里插入图片描述

在这里插入图片描述
一分配,发现第一个内存块剩余的空间只有10字节,end-m 不够,所以就要跳到下一个内存块
然后p=p->d.next,指向了第二个内存块,做相同的操作。

第二个内存块剩余60字节,大于size(11),就分配上了
在这里插入图片描述
last指针向下走,给外边分配11字节的内存空间。然后return掉。

假如连续进行内存申请,申请的内存比较大,也就是说,每次去遍历已有的小块内存的时候,发现都获取不到相应大小的内存块,都是缺少一些字节 。那只能重新开辟一块内存池了。开辟完后,还要做上面所叙述的for循环,把前面都循环一下,前面的内存块的failed都要加加一下。

如果说某个内块的failed大于4了
也就是这个内存块分配了4次都没有成功过,说明当前的内存块剩余的空间非常非常小了,几乎是分配完了,当前内存块就不再使用了。就把pool的current指向下一个内存块,从下边开始遍历,根据failed的值判断下去,加加下去,以此类推。

failed记录当前内存块内存分配失败的次数。
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林林林ZEYU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值