在Libev中,如果某种结构的数组需要扩容,它使用array_needsize宏进行处理,比如:

array_needsize (int, fdchanges, fdchangemax, fdchangecnt, EMPTY2);

这就表示要将整型(int)数组fdchanges,由原来的fdchangemax个元素扩容为fdchangecnt,新扩容的内存空间使用EMPTR2进行初始化。

array_needsize宏定义如下:

#define array_needsize(type,base,cur,cnt,init)                           \
if (expect_false ((cnt) > (cur))) \
{ \
int ecb_unused ocur_ = (cur); \
(base) = (type *)array_realloc(sizeof(type), (base), &(cur), (cnt)); \
init ((base) + (ocur_), (cur) - ocur_); \
}

base是type类型的数组,当前有cur个元素,需要调整到cnt个元素,新扩充的内存空间使用init函数初始化。

该宏的关键在于array_realloc函数,它的实现如下:

static void * array_realloc (int elem, void *base, int *cur, int cnt)
{
*cur = array_nextsize (elem, *cur, cnt);
return ev_realloc (base, elem * *cur);
}

该函数中,首先使用array_nextsize计算最终的元素个数,然后调用ev_realloc申请空间。array_nextsize计算新元素个数的方法如下:

/* find a suitable new size for the given array, */
/* hopefully by rounding to a nice-to-malloc size */
int array_nextsize (int elem, int cur, int cnt)
{
int ncur = cur + 1; do
ncur <<= 1;
while (cnt > ncur); /* if size is large, round to MALLOC_ROUND - 4 * longs to accommodate malloc overhead */
if (elem * ncur > MALLOC_ROUND - sizeof (void *) * 4)
{
ncur *= elem;
ncur = (ncur + elem + (MALLOC_ROUND - 1) + sizeof (void *) * 4) & ~(MALLOC_ROUND - 1);
ncur = ncur - sizeof (void *) * 4;
ncur /= elem;
}
return ncur;
}

该函数中,首先得到一个比cnt大的偶数ncur,如果ncur个元素占用的空间(elem* ncur + sizeof (void *) * 4)大于MALLOC_ROUND(4096)个字节,则需要调整ncur。

这里之所以要加上sizeof(void *) * 4,是因为malloc在申请空间时,除了申请的字节数之外,它还会在内存块之外加上额外的空间,记录当前内存块的信息,也就是sizeof (void *) * 4个字节。

调整ncur的方法,主要是下面的语句:

    ncur *= elem;
ncur = (ncur + elem + (MALLOC_ROUND - 1) + sizeof (void *) * 4) & ~(MALLOC_ROUND - 1);

它的主要作用,就是使得ncur向上调整成MALLOC_ROUND的倍数。这里的ncur代表的是最终申请空间的总字节数。因此,还需要将其调整为元素个数:

    ncur = ncur - sizeof (void *) * 4;
ncur /= elem;

得到最终的元素个数之后,接下来就是调用ev_realloc申请空间了,它的实现如下:

static void *ev_realloc_emul (void *ptr, long size) EV_THROW
{
/* some systems, notably openbsd and darwin, fail to properly
* implement realloc (x, 0) (as required by both ansi c-89 and
* the single unix specification, so work around them here.
* recently, also (at least) fedora and debian started breaking it,
* despite documenting it otherwise.
*/ if (size)
return realloc (ptr, size); free (ptr);
return 0;
} static void *(*alloc)(void *ptr, long size) = ev_realloc_emul; void *ev_realloc (void *ptr, long size)
{
ptr = alloc (ptr, size); if (!ptr && size)
{
fprintf (stderr, "(libev) cannot allocate %ld bytes, aborting.", size);
abort ();
}
return ptr;
}

PS:Libev的代码就分析到这了!

Libev源码分析08:Libev中的内存扩容方法的更多相关文章

  1. Java|ArrayList源码分析|add()增加方法和grow()扩容方法

    本文结构: 1.介绍特点 2.基本方法 3.重点源码分析 1.介绍特点 ArrayList: 是List的一个具体实现子类,是List接口的一个数组实现 (里面必定维护了一个数组). 默认初始容量10 ...

  2. Libev源码分析08:Libev中的信号监视器

    Libev中的信号监视器,用于监控信号的发生,因信号是异步的,所以Libev的处理方式是尽量的将异步信号同步化.异步信号的同步化方法主要有:signalfd.eventfd.pipe.sigwaiti ...

  3. [转]Libev源码分析 -- 整体设计

    Libev源码分析 -- 整体设计 libev是Marc Lehmann用C写的高性能事件循环库.通过libev,可以灵活地把各种事件组织管理起来,如:时钟.io.信号等.libev在业界内也是广受好 ...

  4. angular源码分析:angular中脏活累活的承担者之$interpolate

    一.首先抛出两个问题 问题一:在angular中我们绑定数据最基本的方式是用两个大括号将$scope的变量包裹起来,那么如果想将大括号换成其他什么符号,比如换成[{与}],可不可以呢,如果可以在哪里配 ...

  5. angular源码分析:angular中入境检察官$sce

    一.ng-bing-html指令问题 需求:我需要将一个变量$scope.x = '<a href="http://www.cnblogs.com/web2-developer/&qu ...

  6. angular源码分析:angular中各种常用函数,比较省代码的各种小技巧

    angular的工具函数 在angular的API文档中,在最前面就是讲的就是angular的工具函数,下面列出来 angular.bind //用户将函数和对象绑定在一起,返回一个新的函数 angu ...

  7. angular源码分析:angular中的依赖注入式如何实现的

    一.准备 angular的源码一份,我这里使用的是v1.4.7.源码的获取,请参考我另一篇博文:angular源码分析:angular源代码的获取与编译环境安装 二.什么是依赖注入 据我所知,依赖注入 ...

  8. spark 源码分析之十六 -- Spark内存存储剖析

    上篇spark 源码分析之十五 -- Spark内存管理剖析 讲解了Spark的内存管理机制,主要是MemoryManager的内容.跟Spark的内存管理机制最密切相关的就是内存存储,本篇文章主要介 ...

  9. Libev源码分析09:select突破处理描述符个数的限制

    众所周知,Linux下的多路复用函数select采用描述符集表示处理的描述符.描述符集的大小就是它所能处理的最大描述符限制.通常情况下该值为1024,等同于每个进程所能打开的描述符个数. 增大描述符集 ...

随机推荐

  1. java的boolean和Boolean

    boolean是基本数据类型Boolean是它的封装类,和其他类一样,有属性有方法,可以new,例如: Boolean bl= new Boolean("true"); // bo ...

  2. day38 08-Spring的id、name和scope顺序

    访问的路径的是/login.id不允许出现特殊的字符./是特殊的字符.Struts 2已经没有/,action的名字已经不带/了.现在的开发中一般使用id这个属性即可. 这个类在被Spring创建的时 ...

  3. Leetcode73. Set Matrix Zeroes矩阵置零

    给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0.请使用原地算法. 示例 1: 输入: [   [1,1,1],   [1,0,1],   [1,1,1] ] 输 ...

  4. Leetcode96.Unique Binary Search Trees不同的二叉搜索树

    给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 假设n个节点存在二叉排序树的 ...

  5. mybatis中实现一对一,一对多查询

    在实际的开发中我们经常用到的是一对一查询和一对多查询.而多对多的实现是通过中间来实现,这里就没有给出来了 比如: 订单和用户是一对一的关系(一个订单只能对应一个用户) 订单和订单明细是一对多的关系(一 ...

  6. sklearn之特征提取(文本特征)

    1.引言 关于文本的提取有很多方法,本文主要探索下sklearn官方的文本特征提取功能. 2.文本特征提取 文本分析是机器学习算法的主要应用领域. 然而,原始数据,符号文字序列不能直接传递给算法,因为 ...

  7. DIV元素垂直居中的分析与实现

    首先,对于需要垂直居中的元素常规居中处理 margin: 0 auto; 接下来要设置div的祖先元素的宽高为100%, 在默认的设置中他们都为0: html, body { width: %; he ...

  8. WebWork(在主线程创建子进程)

    WebWork浅谈 前言: 都知道JS是单线程语言,最让人头疼的莫过于在网络正常的情况下经常出现页面的假死, 以及在进行大量的for循环计算时会导致线程阻塞,由于要进行大量的计算JS后面的运行会被阻隔 ...

  9. 虚幻UE4的后处理特效介绍 http://www.52vr.com/thread-31215-1-1.html

    转载 虚幻UE4提供了后处理特效的功能,可以实现景深,光溢出,色调调整,饱和度等等.要使用虚幻4的后处理,就一定要用到PostProcessVolumn,这是一种特殊的体积,可以放置在场景中的任何位置 ...

  10. LintCode_111 爬楼梯

    题目 假设你正在爬楼梯,需要n步你才能到达顶部.但每次你只能爬一步或者两步,你能有多少种不同的方法爬到楼顶部? 比如n=3,中不同的方法 返回 3 1 2 3 5 8 13... step[2] = ...