热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Swoole源码学习记录(三)——三种MemoryPool(下)

swoole版本:1.7.4-stableGithub地址:https:github.comLinkedDestinyswoole-src-analysis接下来

swoole版本:1.7.4-stable

Github地址: https://github.com/LinkedDestiny/swoole-src-analysis

接下来是RingBuffer。这相当于一个循环数组,每一次申请的一块内存在该数组中占据一个位置,这些内存块是可以不等长的,因此每个内存块需要有一个记录其长度的变量。这里贴出swRingBuffer_head结构体的代码:

typedef struct _swRingBuffer_item
{
volatileuint32_t lock;
volatileuint32_t length;
} swRingBuffer_head;

每一个结构体代表一个RingBuffer中的内存块,其中lock变量标记该内存块是否被占用,length变量标记该内存块的长度。

接着是swRingBuffer结构体的声明:

typedef struct _swRingBuffer
{
uint8_t shared; //可共享
size_t size; //内存池大小
volatile off_talloc_offset; // 分配内存的起始长度
volatile off_tcollect_offset; // 可用内存的终止长度
volatileuint32_t free_n; // 有多少个内存块待回收
void *memory; // 内存池的起始地址
} swRingBuffer;

每一个结构体代表一个RingBuffer内存池。这里先要说明一下RingBuffer的三个变量:alloc_offset,collect_offset,free_n。

alloc_offset变量是分配内存的起始地址,代表的是RingBuffer现有的可用空间的起始地址;collect_offset变量是分配内存的终止地址,代表的是RingBuffer现有的可用空间的结束地址。为了方便理解,大家可以想象一下循环队列,alloc_offset和collect_offset就是标记队头和队尾的标记,每一次分配内存就相当于入队,每一次释放内存就相当于出队。

而free_n变量是用于标记当前还有多少个已释放的内存块待回收。这是因为RingBuffer采用的是连续分配,可能会存在一些已经被free的内存块夹在两个没有free的内存块中间,没有被立即回收,就需要一个变量去通知内存池回收这些内存。。

    RingBuffer的创建函数为swRingBuffer_new,其声明在swoole.h文件的514 – 517行。入下:

/**
* RingBuffer, Inorder for malloc / free
*/
swMemoryPool *swRingBuffer_new(size_t size, uint8_tshared);

该函数的具体定义在RingBuffer.c中,创建过程与FixedPool基本类似,就不再额外分析,大家自行阅读源码即可。

    和FixedPool类似,RingBuffer也拥有4个函数用于操作内存池,其函数声明如下:

static void swRingBuffer_destory(swMemoryPool *pool);
static sw_inline void swRingBuffer_collect(swRingBuffer*object);
static void* swRingBuffer_alloc(swMemoryPool *pool,uint32_t size);
static void swRingBuffer_free(swMemoryPool *pool, void*ptr);

其中alloc、destroy、free三个函数的功能很明确,swRingBuffer_collect函数用于回收已经不被占用的内存。这里着重分析alloc函数和collect函数。

首先是collect函数。在发现内存池剩余不足或分配内存结束后,RingBuffer都会调用collect函数去回收已经没有被占用的内存。其核心代码如下:

  

  for(i = 0;i    {
item =(swRingBuffer_head *) (object->memory + object->collect_offset);

swTraceLog(SW_TRACE_MEMORY,"collect_offset=%d, item_length=%d, lock=%d",object->collect_offset, item->length, item->lock);

//cancollect
if(item->lock == 0)
{
object->collect_offset+= (sizeof(swRingBuffer_head) + item->length);
if(object->free_n > 0)
{
object->free_n--;
}
if(object->collect_offset >= object->size)
{
object->collect_offset= 0;
}
}
else
{
break;
}
}

源码解释:每一次循环,都会获取当前collect_offset指向的地址代表的内存块,并获取其swRingBuffer_head结构,如果该内存块已经被free,则将collect_offset标记后移该内存块的长度,回收该内存。如果发现collect_offset超出了内存池大小,则将collect_offset移到内存池头部。

alloc函数太长,在此不贴出源码,只写出伪代码供分析:

start_alloc:
if( alloc_offset {
head_alloc:
计算剩余内存大小

if( 内存足够 )
gotodo_alloc
else if( 内存不足且已经回收过内存)
return NULL;
else
{
try_collect = 1;
调用collect
goto start_alloc
}
}
else // 起始地址在终止地址右侧(终止地址被移动到了首部)
{
计算从alloc_offset到内存池尾部的剩余内存大小
if( 内存足够 )
gotodo_alloc
else
{
标记尾部剩余内存为可回收状态
将alloc_offset移动到首部
gotohead_alloc
}
}
do_alloc:
实际分配内存块并设置属性,移动alloc_offset标记
如果free_n大于0,则回收内存。

最后是MemoryGlobal。MemoryGlobal是一个比较特殊的内存池。说实话我没有看懂它的作用,所以我决定先暂时跳过MemoryGlobal,等了解其具体使用场景时再来分析这一块。


推荐阅读
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 小程序的授权和登陆
    小程序的授权和登陆 ... [详细]
  • 本文介绍了 Go 语言中的高性能、可扩展、轻量级 Web 框架 Echo。Echo 框架简单易用,仅需几行代码即可启动一个高性能 HTTP 服务。 ... [详细]
  • Cookie学习小结
    Cookie学习小结 ... [详细]
  • 通过将常用的外部命令集成到VSCode中,可以提高开发效率。本文介绍如何在VSCode中配置和使用自定义的外部命令,从而简化命令执行过程。 ... [详细]
  • PHP语言之所以能有今天的地位,得益于PHP语言设计者一直遵从实用主义,将技术的复杂性隐藏在底层。PHP语言入门简单,容易掌握,程序健壮性好。 ... [详细]
  • php怎么做rpc通信(RPC通信)
    导读:很多朋友问到关于php怎么做rpc通信的相关问题,本文编程笔记就来为大家做个详细解答,供大家参考,希望对大家有所帮助!一起来看看吧!本文目录一览: ... [详细]
  • 哪里有php培训(php培训哪家好)
    导读:今天编程笔记来给各位分享关于哪里有php培训的相关内容,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: ... [详细]
  • 电商系统设计艺术——秒杀业务设计
    一、秒杀场景人多货少,只有少量的人能够抢购成功。高并发,秒杀业务在开始之前流量比较平稳,开始后流量会直线性的上升。持续时间短࿰ ... [详细]
  • redis 获取不到_redis 缓存锁的实现方法
    1.redis加锁分类redis能用的的加锁命令分表是INCR、SETNX、SET2.第一种锁命令INCR这种加锁的思路是,key不存在,那么key的值 ... [详细]
  • 【宇润日常疯测007】Swoole 协程与传统 fpm 同步模式比较
    为什么80%的码农都做不了架构师?如果说数组是PHP的精髓,数组玩得不6的,根本不能算是会用PHP。那协程对于Swoole也是同理& ... [详细]
  • PHP socket服务端与客户端的简易通信
    今天学习socket通信的同时,顺便整理了下以前初识socket的知识。现在关于php的socket通信,有些框架已经十分成熟了,比如swoole和workerman,这两个大家可以学习学 ... [详细]
  • 本文介绍了如何查看PHP网站及其源码的方法,包括环境搭建、本地测试、源码查看和在线查找等步骤。 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送www方式的数据。HTTP协议采用了请求响应模型。客服端向服务器发送一 ... [详细]
author-avatar
Liushan2502897753
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有