首页 >> 大全

freeswitch APR库内存池

2023-10-11 大全 34 作者:考证青年

概述

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

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

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

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

环境

: 7.0 (Final)或以上版本

:v1.8.7

GCC:4.8.5

内存池源码

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

libs\apr\include\apr_pools.hlibs\apr\memory\unix\apr_pools.c

内存池结构体的定义在.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_THREADSapr_thread_mutex_t   *user_mutex;#endif#if !APR_POOL_DEBUGapr_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_THREADSapr_os_thread_t       owner;apr_thread_mutex_t   *mutex;#endif /* APR_HAS_THREADS */#endif /* APR_POOL_DEBUG */#ifdef NETWAREapr_os_proc_t         owner_proc;#endif /* defined(NETWARE) */};

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

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

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

常用函数

查看源代码头文件libs\apr\\.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);…

使用函数创建内存池

使用函数清空内存池

使用函数销毁整个内存池

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

创建

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

传入参数父节点为空,则使用作为父节点传入参数内存分配失败回调函数为空,则使用父节点的回调函数传入参数分配器为空,则使用父节点的分配器使用分配器获取一块内存节点node,大小为“ - ”初始化内存池pool,对“pool->”赋值为节点node

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

清空clear

代码逻辑。

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

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

销毁

的代码逻辑。

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

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

分配alloc

接口的代码逻辑。

传入参数size按照8字节做内存对齐检查pool->节点数据,如果节点剩余空间满足分配请求的大小,则直接在pool->节点分配空间并返回。获取pool->->next节点,检查节点数据。 如果节点剩余空间满足分配请求的大小,则将该节点从list中删除,保存为node节点。如果节点剩余空间不满足,则使用pool->分配器获取大小为size的内存节点,保存为node节点。修改node节点数据,记录node->并作为分配请求的返回数据,修改node->起始空间点+size。将node节点插入列表的首位。判断node节点的剩余空间,并将列表按照node节点剩余空间的大小由大到小排序 。

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

自动扩展的问题

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

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

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

总结

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

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

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

空空如常

求真得真

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了