`
liuzhaomin
  • 浏览: 204278 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Apache数组分析

阅读更多
3.1数组
3.1.1数组概述
数组是Apache中最经常也是最普通的数据结构,尽管C语言中已经提供了一定的数组功能,但是C语言数组运用到Apache中还存在下面的一些问题:
(1)、C语言中的数组在定义的时候就必须确定维数目,一旦确定,其长度就不可更改。但是Apache中很多情况并不知道数组中能够保存的最大数目,如果预定义的太大,可能会浪费过多的空间;定义的太小又可能不能满足系统要求;因此Apache中需要一种动态的具有弹性伸缩能力的数组,这样实际需要多少元素就分配多少元素;
(2)、C语言中提供了另外一种数组动态伸缩的方案,即就是使用malloc分配空间,将空间看作数组进行处理。不过对于malloc分配的空间只能保存一种类型的数据。如果需要保存其余类型,则需要重新分配。
Apache中的数组实现方案类似于STL或者Java中的Vector,其长度可以保持动态变化,而且其中可以存放不同类型的数据,包括基本数据类型到复合数据类型。
3.1.2数组结构
Apache中相关的数组结构都定义在文件apr_table.h和apr_table.c中了。apr_array_header_t结构是Apache的核心结构,其定义如下:
struct apr_array_header_t {
apr_pool_t *pool;
int elt_size;
int nelts;
int nalloc;
char *elts;
};
数组的结构示意图片可以用下图表示:
图2.1 Apache数组结构图
apr_array_header_t结构中的elts指针指向了实际的用malloc分配的空间,每个空间的大小为elt_size。由于数组元素的个数是可以动态变化的,因此结构中使用nalloc记录当前已经分配的数组中的元素个数。另外由于Apache中的数组元素并不是所有的都被用到,因此还需要nelts记录当前已经使用的元素个数,自然剩余的可以利用的数组元素个数为nalloc-nelts。分配数组所需要的所有空间都从内存池pool中获取。
3.1.3创建数组
数组的创建通过调用apr_array_make实现,不过其内部主要工作由make_array_core实现:
static void make_array_core(apr_array_header_t *res, apr_pool_t *p,int nelts, int elt_size, int clear)
{
if (nelts < 1) {
nelts = 1;
}
if (clear) {
res->elts = apr_pcalloc(p, nelts * elt_size);
}
else {
res->elts = apr_palloc(p, nelts * elt_size);
}
res->pool = p;
res->elt_size = elt_size;
res->nelts = 0; /* No active elements yet... */
res->nalloc = nelts; /* ...but this many allocated */
}
APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p,int nelts, int elt_size)
{
apr_array_header_t *res;
res = (apr_array_header_t *) apr_palloc(p, sizeof(apr_array_header_t));
make_array_core(res, p, nelts, elt_size, 1);
return res;
}
apr_array_make函数负责主要用于分配apr_array_head_t头结构,而make_array_core则主要负责创建和初始化res元素数组。Res数组的大小中每一个元素的大小为elt_size,总元素个数为nelts,因此分配的总空间为nelts*elt_size,空间分配后继续初始化apr_array_header_t结构中的成员。如果clear为1,则调用apr_pcalloc进行分配,否则调用apr_palloc,两者唯一的区别就是apr_pcalloc会对分配的空间进行初始化清零;而apr_palloc则不会初始化。
除了从头开始创建一个新的数组之外,APR中还允许使用apr_array_copy将一个数组拷贝到一个新的数组:
APR_DECLARE(apr_array_header_t *) apr_array_copy(apr_pool_t *p,const apr_array_header_t *arr)
Arr是需要拷贝的源数组,拷贝后的数组由函数返回。拷贝函数内部首先定义一个arp_array_header_t的变量res,从内存池p中为其分配足够的空间,然后调用make_array_core生成一个与arr数组大小相同的数组,再调用memcpy逐一进行内存拷贝。然后返回该空间。
3.1.4元素压入和弹出
Apache中对数组元素的操作类似于堆栈,只允许弹出(pop)和压入(push)两种,因此你无法象在C语言中随意的访问数组中的元素。
当数据需要保存到数组中的时候,通过函数apr_array_push函数进行,其原型声明如下:
APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr)
arr是需要保存到数组中的元素。元素的保存按照从左到右,即从低索引到高索引依次存储,不可能出现C语言中的随机保存的情况,因此从这个角度而言,数组称之为堆栈更合适。
在将元素压入数组之前函数首先检查数组中是否有可用的空闲空间;如果有剩余可用空间,其将直接将元素拷贝到第nelts+1数组的位置,调整nelts为nelts++,同时返回该元素。如果没有,即意味着当前数据中nalloc个空间都已经被使用,即nelts=nalloc,那么此时必须扩大数组空间用来保存压入的数据。不过数组空间的增加并不是需要几个就增加几个,而是遵循下面的批量增加原则:
■ 如果压入数据之前nalloc为0,即尚未分配任何空间,那么此时只创建大小为elt_size的空间,即一个元素的空间。
■ 如果当前元素压入之前,系统分配的nalloc个单元都已经被使用完毕,那么此时将直接批量一次性将空间扩大到nalloc*2个元素空间。
一旦分配完这些空间,第一个可用的空闲空间则是第nalloc+1个元素。此时只需要将需要压入的元素拷贝到该地址空间即可,拷贝完之后,将elt_size加一,并返回新元素的地址。
与apr_array_push类似,Apache提供了另外的一个版本的压入函数apr_array_push_noclear,该函数与apr_array_push函数功能基本类似,其唯一区别正如函数名称,在于“noclear”。 apr_array_push在产生新的空闲块,压入新元素之前调用memset对新内存块进行清零操作,而“noclear”函数则省去了这一步。
与元素压入匹配,从数组中取元素通过函数apr_array_pop进行,其函数声明如下:
APR_DECLARE(void *) apr_array_pop(apr_array_header_t *arr)
元素弹出遵循先进先出的弹出原则,因此被弹出的元素永远都是第nelts个,除非当前的数组为空,不在有任何的有效数据。返回语句可以简化为return arr->elts + (arr->elt_size * (--arr->nelts));
3.1.5数组合并
Apache中使用apr_array_cat将两个元素进行合并,函数定义如下:
APR_DECLARE(void) apr_array_cat(apr_array_header_t *dst,const apr_array_header_t *src)
函数将数组src添加到数组dst的末尾。函数首先检查当前的空闲单元能不能容下src数组,这里容纳的概念并不是容纳src中的nalloc个元素,而仅仅是容纳下src中的nelts个非空闲单元,并不包括nalloc-nelts空闲单元,因此函数需要比较的是(dst->nalloc) - (dst->nelts) >= (src->nelts),而不是(dst->nalloc) - (dst->nelts) >= (src->nalloc)。如果能够容纳,则没有必要分配新的空间,直接内存拷贝就可以了。
如果dst中所有的空闲空单元都不够存放src中的空闲单元,那么此时毫无疑问dst需要分配新的空间,分配算法如下:
1)、如果dst中元素个数为零,此时,将产生一个新的空间。
2)、如果dst中元素个数nalloc不为零,则首先产生nalloc*2个空闲空间。
3)、尽管如此,如果src的非空闲元素实在太多,而dst本身空闲空间很小,那么即使一次产生 nalloc个空闲块也不一定能够盛放src中的元素。唯一的办法就是不停的产生新的空闲块,每次产生后的总块数都是当前的一倍,直到空闲块总数能够容纳src中的非空闲元素为止。这真是下面的代码所做的事情:
if (dst->nelts + src->nelts > dst->nalloc) {
int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2;
while (dst->nelts + src->nelts > new_size) {
new_size *= 2;
}
}
一旦确定确定需要产生的空闲块的总数,函数将一次性从内存池dst->pool中申请。然后将src中的数据拷贝空间空间即可。

关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish1234 at sina.com.cn与之联系!

如果你觉得本文不错,请点击文后的“推荐本文”链接!!
分享到:
评论

相关推荐

    axis自定义数组对象

    #### 三、示例代码分析 为了更好地理解如何在Axis框架下使用自定义数组对象,我们将通过一个具体的示例来逐步解析其工作原理。 **1. 定义自定义数组对象** ```java public class Bean implements Serializable { ...

    Apache源代码内核分析

    ### Apache源代码内核分析——内存池管理机制详解 #### 一、引言 Apache作为全球广泛使用的Web服务器软件之一,其稳定性和高效性在很大程度上依赖于良好的内存管理机制。尤其是在高并发环境下,如何有效地管理和...

    有一个int数组{1,3,5,-2,4,6},要求获取:最大值、最小值、元素和、平均值

    在IT领域,数组是最基本的数据结构之一,广泛应用于各种算法和...总之,理解和掌握如何计算数组的最大值、最小值、元素和以及平均值是编程和数据分析的基础,无论是在简单的练习还是复杂的项目中,都有着广泛的应用。

    数组函数.zip

    9. **并行和分布式计算**:对于大型数据集,可以使用并行或分布式数组函数,如Python的`multiprocessing`库,或者大数据处理框架如Apache Spark。 10. **数组函数的应用**:在数据分析(如统计计算)、机器学习(如...

    Apache源代码全景分析.pdf

    ### Apache源代码全景分析——内存池机制深度剖析 #### 一、引言 Apache作为一款高性能的Web服务器软件,其内部实现中一个重要的组件便是内存池管理机制。本篇文章将从给定的文档《Apache源代码全景分析.pdf》中...

    开源项目-apache-arrow.zip

    Apache Arrow 的设计考虑了云计算、流处理和机器学习等现代数据分析场景。 在 "Review initial support for lists in Go-Arrow" 这个描述中,我们关注的是Go语言版本的Arrow库对于列表类型的支持。在列式存储中,...

    apache源代码全景分析

    ### Apache源代码全景分析——内存池机制深度剖析 #### 一、引言 Apache作为一款高性能的Web服务器软件,其内部实现中一个重要的组件便是内存池。本文将深入探讨Apache中内存池的设计理念、实现机制及其在实际应用...

    poi-3.9 apache-poi-3.9 最新稳定版本

    它们可以处理简单的数学公式到复杂的数组公式和嵌套公式。 7. 导入导出:Apache POI提供了一套完整的API,用于将Java数据结构转换为Excel文件,或者从Excel文件中读取数据到Java对象。这使得它成为数据导入导出的...

    Apache Commons Math3探索之多项式曲线拟合实现代码

    首先,我们要知道多项式曲线拟合是数据分析和科学计算中的常见任务,它通过找到一个多项式函数来最好地逼近给定的一组数据点。Apache Commons Math3提供的`PolynomialCurveFitter`类实现了这一功能。该类允许我们...

    apache commons 开源工具列举

    1. **Apache Commons Lang**: 这个模块提供了一系列高级的Java语言功能,包括字符串操作(如格式化、比较、拼写检查)、数组操作、日期和时间处理、反射工具等。例如,StringUtils类提供了大量的静态方法,可以方便...

    求出java中int数组的 cv值

    如果你需要处理大量数据或进行更复杂的统计分析,Apache Commons Math库提供了许多其他功能,如平均值、中位数、标准差等,这些都是进行数据分析时非常有用的工具。对于初学者来说,理解这些统计概念以及如何使用...

    apache com包

    4. **源码分析**: 压缩包中的`commons-lang-2.5-src`文件表示的是Apache Commons Lang 2.5版本的源代码。通过阅读源码,开发者可以深入了解这些工具类的工作原理,学习优秀的设计模式和编程技巧,这对于提升Java编程...

    php+mysql和apache入门经典(第五版)源码

    通过分析和修改这些代码,你可以更好地理解如何将PHP脚本连接到MySQL数据库,如何使用PHP处理用户输入,以及如何在Apache环境下部署和运行这些程序。这些实践经验对于提升编程技能和解决问题的能力至关重要。 在...

    apache-common最全的jar包

    这个压缩包包含了一些 Apache Commons 的核心模块,让我们逐一分析这些 jar 包所代表的知识点。 1. **commons-math-2.2.jar**: 这是 Apache Commons Math 库,提供了一系列数学和统计计算功能,包括线性代数、...

    Apache Commons书籍

    2. **Apache Commons Lang**:提供了一些增强的Java语言功能,比如字符串操作、数组处理、日期和时间处理、反射工具等。例如,StringUtils提供了丰富的字符串处理方法,ClassUtils帮助处理类和类加载器问题。 3. **...

    org.apache.commons 的 jar 包 源码

    总的来说,分析和学习 "org.apache.commons" 的源码是提升Java开发技能的好方法,它可以帮助你更好地理解和应用这些广泛使用的工具类库,提高编程效率和代码质量。同时,参与开源社区,提交补丁或新功能,也是贡献...

    apache commons lang、io、collection源码与UT

    Commons Collection 提供了对Java集合框架的扩展,包括多维数组、堆栈、队列、映射等功能。例如,ListUtils 提供了列表操作,如 union 和 intersection,而 MapUtils 则提供了对Map的操作,如 createMap 和 isEmpty...

Global site tag (gtag.js) - Google Analytics