概述

freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性。

apr库中的大部分API都需要依赖于内存池,使用内存池简化内存管理,提高内存分配效率,减少内存操作中出错的概率。

在fs的自定义模块开发中,我们也会用到内存池来操作内存,所以要对内存池的基本操作和使用限制有一定了解,防止错误的使用,导致程序运行问题。

下面我们对apr的内存池接口做一个介绍。

环境

centos:CentOS  release 7.0 (Final)或以上版本

freeswitch:v1.8.7

GCC:4.8.5

内存池源码

apr库的内存池源代码文件在libs/apr目录下

libs\apr\include\apr_pools.h

libs\apr\memory\unix\apr_pools.c

内存池结构体apr_pool_t的定义在apr_pools.c文件中

struct apr_pool_t {

apr_pool_t           *parent;

apr_pool_t           *child;

apr_pool_t           *sibling;

apr_pool_t          **ref;

cleanup_t            *cleanups;

cleanup_t            *free_cleanups;

apr_allocator_t      *allocator;

struct process_chain *subprocesses;

apr_abortfunc_t       abort_fn;

apr_hash_t           *user_data;

const char           *tag;

#if APR_HAS_THREADS

apr_thread_mutex_t   *user_mutex;

#endif

#if !APR_POOL_DEBUG

apr_memnode_t        *active;

apr_memnode_t        *self; /* The node containing the pool itself */

char                 *self_first_avail;

#else /* APR_POOL_DEBUG */

apr_pool_t           *joined; /* the caller has guaranteed that this pool

* will survive as long as ->joined */

debug_node_t         *nodes;

const char           *file_line;

apr_uint32_t          creation_flags;

unsigned int          stat_alloc;

unsigned int          stat_total_alloc;

unsigned int          stat_clear;

#if APR_HAS_THREADS

apr_os_thread_t       owner;

apr_thread_mutex_t   *mutex;

#endif /* APR_HAS_THREADS */

#endif /* APR_POOL_DEBUG */

#ifdef NETWARE

apr_os_proc_t         owner_proc;

#endif /* defined(NETWARE) */

};

从结构体的定义来看,在使用内存池的过程中主要关注“apr_memnode_t *active;”和“char *self_first_avail;”俩个变量。

变量active是当前内存池中内存节点链表的第一个节点,也可以从名字理解是活动节点。

变量self_first_avail是当前内存池中可用内存的起始点。

常用函数

查看源代码头文件libs\apr\include\apr_pools.h

APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool, apr_pool_t *parent);

APR_DECLARE(void) apr_pool_clear(apr_pool_t *p);

APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);

APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size);

使用apr_pool_create函数创建内存池

使用apr_pool_clear函数清空内存池

使用apr_pool_destroy函数销毁整个内存池

使用apr_palloc函数从内存池获取指定大小的内存块

创建create

apr_pool_create接口是apr_pool_create_ex的简化版,省略了4个参数中的后俩个,简化了用户的调用过程,下面我们介绍apr_pool_create_ex的代码逻辑。

  1. 传入参数parent父节点为空,则使用global_pool作为父节点
  2. 传入参数abort_fn内存分配失败回调函数为空,则使用父节点的回调函数
  3. 传入参数allocator分配器为空,则使用父节点的allocator分配器
  4. 使用allocator分配器获取一块内存节点node,大小为“MIN_ALLOC - APR_MEMNODE_T_SIZE”
  5. 初始化内存池pool,对“pool->active”赋值为节点node

这里可以看出内存池pool刚创建的时候,“pool->active”变量只有一个内存节点,大小为“MIN_ALLOC - APR_MEMNODE_T_SIZE”,根据宏定义计算大小为8192-40=8152字节。

清空clear

apr_pool_clear代码逻辑。

  1. 销毁内存池pool的所有子内存池。
  2. 清理pool中的额外设置,包括cleanup、subprocess和user_data。
  3. 重置pool->active,保留1个内存节点并重置起点,释放多余节点。

经过clear的内存池pool,回归到了刚刚create出来的状态。

销毁destory

apr_pool_destroy的代码逻辑。

  1. 销毁内存池pool的所有子内存池。
  2. 清理pool中的额外设置,包括cleanup、subprocess和父节点指针。
  3. 释放pool->active所有节点。
  4. 销毁当前内存池拥有的allocator分配器。

经过destory的内存池,占用的所有内存都会释放掉。

分配alloc

apr_palloc接口的代码逻辑。

  1. 传入参数size按照8字节做内存对齐
  2. 检查pool->active节点数据,如果节点剩余空间满足分配请求的大小,则直接在pool->active节点分配空间并返回。
  3. 获取pool->active->next节点,检查节点数据。

    a)      如果节点剩余空间满足分配请求的大小,则将该节点从list中删除,保存为node节点。

    b)      如果节点剩余空间不满足,则使用pool->allocator分配器获取大小为size的内存节点,保存为node节点。

  1. 修改node节点数据,记录node->first_avail并作为分配请求的返回数据,修改node->first_avail起始空间点+size。
  2. 将node节点插入active列表的首位。
  3. 判断node节点的剩余空间,并将active列表按照node节点剩余空间的大小由大到小排序 。

经过多次apr_palloc后,pool->active节点列表会产生多个新的节点,组成node链表。

自动扩展的问题

从分配alloc的代码逻辑可以看出,当内存池的空间不足时,apr_palloc会生成新的node节点扩展内存池空间。

内存池的内存空间并非是连续的,而是以单向链表的形式组合多个node节点,并且没有node个数的限制,理论上可以无限扩展直到内存被占满。

apr内存池没有内存回收接口,即使有内存空间明确不再需要使用,apr_pools也没有提供对应的回收接口,除非对整个内存池执行clear或者destroy,才能回收整个内存池空间。

总结

从apr库内存池的接口逻辑来看,该内存池更多适用于会话式场景,一个新的会话对应一个内存池,会话结束后,直接对内存池整体回收,简化会话过程中的内存管理。

而对于更长的生命周期的代码逻辑来说,使用上需要注意内存占用问题,防止内存的无限增长。

另外,apr内存池还有一些特性(包括调试、多线程、分配失败回调、子池等)需要更深入的学习和测试。


空空如常

求真得真

freeswitch APR库内存池的更多相关文章

  1. freeswitch APR库

    概述 freeswitch依赖库源代码基本都可以在libs目录下找到. 在freeswitch的官方手册中,可以找到freeswitch的依赖库表格,其中freeswitch的core核心代码依赖库主 ...

  2. freeswitch APR库哈希表

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. 哈希表在开发中应用的非常广泛,主要场景是对查询效率要求较高的逻辑,是典型的空间换时间的数据结构实现. 大多数 ...

  3. freeswitch APR-UTIL库线程池实现分析

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. APR库在之前的文章中已经介绍过了,APR-UTIL库是和APR并列的工具库,它们都是由APACHE开源出来 ...

  4. freeswitch APR库线程读写锁

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. 线程读写锁在多线程服务中有重要的作用.对于读数据比写数据频繁的服务,用读写锁代替互斥锁可以提高效率. 由于A ...

  5. Linux简易APR内存池学习笔记(带源码和实例)

    先给个内存池的实现代码,里面带有个应用小例子和画的流程图,方便了解运行原理,代码 GCC 编译可用.可以自己上网下APR源码,参考代码下载链接: http://pan.baidu.com/s/1hq6 ...

  6. freeswitch APR-UTIL库消息队列实现

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. APR库在之前的文章中已经介绍过了,APR-UTIL库是和APR并列的工具库,它们都是由APACHE开源出来 ...

  7. 不定长内存池之apr_pool

    内存池可有效降低动态申请内存的次数,减少与内核态的交互,提升系统性能,减少内存碎片,增加内存空间使用率,避免内存泄漏的可能性,这么多的优点,没有理由不在系统中使用该技术. 内存池分类: 1.      ...

  8. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  9. boost的线程池和内存池 智能指针

    内存池为boost自带的 #include <boost/pool/pool.hpp> 或者另外一个开源的库: nedmalloc 一个高效率的库 线程池需要下载另外一个开源库 http: ...

  10. nginx源码学习----内存池

    最近在进行监控平台的设计,之前一直觉得C/C++中最棘手的部分是内存的管理上,远不止new/delete.malloc/free这么简单.随着代码量的递增,程序结构复杂度的提高.各种内存方面的问题悄然 ...

随机推荐

  1. Java并发(十七)----变量的线程安全分析

    1.成员变量和静态变量是否线程安全 如果它们没有共享,则线程安全 如果它们被共享了,根据它们的状态是否能够改变,又分两种情况 如果只有读操作,则线程安全 如果有读写操作,则这段代码是临界区,需要考虑线 ...

  2. 【笔记整理】requests使用代理

    使用proxies参数传递代理信息 import requests if __name__ == '__main__': proxies = { # 这个字典的key不可以乱写,必须是http和htt ...

  3. 虚拟化H搭建

    虚拟化H搭建 H搭建所需要的硬件配置 最大值:所有组件不能超过160个cpu 按安装H需要2G内存+若干个guest(不明确多大),最大支持2个TB内存 最小磁盘2G 一个千兆网卡 lscpu信息 [ ...

  4. JavaFx 打开一个新窗口和窗口交互(四)

    JavaFx 打开一个新窗口和窗口交互(四) JavaFX 从入门入门到入土系列 前面我演示的demo都是单个窗口,那么如何实现多个窗口呢?使用Stage secondStage = new Stag ...

  5. ubuntu frame 个人开发心得

    引言 有一次我在树莓派上安装 Ubuntu Core 我给创新创业项目开发一个可视化 gui 看板,用于展示数据. 然后我就找到了我需要的工具 Ubuntu Frame 初次尝试使用 Ubuntu F ...

  6. 【独立闯天下】Prim新传奇!💥原团队的Blazor版本迟迟无音,合并请求石沉大海。于是,我们决定单干!加入Prime Blazor版项目,一起开创崭新的旅程吧!🌟📚

    共建Prime的Blazor版:为开源社区注入新活力 Prime组件库作为一款广受欢迎的开源组件库,一直以来都备受开发者们的青睐.然而,随着技术的不断发展和更新,原团队的Blazor版本似乎已经逐渐失 ...

  7. 2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程中,第 1、3、5... 次跳跃称为奇数跳跃 而第 2、4、6... 次跳跃称为偶数跳跃 你可以按以下

    2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程中,第 1.3.5... 次跳跃称为奇数跳跃 而第 2.4.6... 次跳跃称为偶数跳跃 你可以按以下 ...

  8. 为什么浏览器会提示网站“不安全”?一文读懂https协议与SSL证书

    [摘要] 为什么浏览器会提示网站"不安全"?从浏览器的"不安全"提示来详细了解https与SSL证书.我们打开很多http网站时候,会看到浏览器提示" ...

  9. 8种ETL算法汇总大全!看完你就全明白了

    摘要:ETL是将业务系统的数据经过抽取.清洗转换之后加载到数据仓库的过程,是构建数据仓库的重要一环,用户从数据源抽取出所需的数据,经过数据清洗,最终按照预先定义好的数据仓库模型,将数据加载到数据仓库中 ...

  10. EDS从小白到专家丨打造你的专属“数据物流”系统

    "数据快递"如何支撑便捷就医?本期让我们来了解如何使用EDS打造专属的"数据物流"系统...... 本文分享自华为云社区<[EDS从小白到专家]第2期-E ...