• Libev源码分析08:Libev中的内存扩容方法


             在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的代码就分析到这了!

  • 相关阅读:
    使用nmon进行系统监控
    linux中内存使用原理
    测试网站访问速度的5个方法
    手机站点击商务通无轨迹解决方法
    PHP开启伪静态配置
    Phpcms V9当前栏目及所有二级栏目下内容调用标签
    手机访问网跳转到手机端
    移动端web开发技巧 -- 转载
    php错误:You don't have permission to access / on this server.
    Navicat for MySQL使用手记(上)--创建数据库和表
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247093.html
Copyright © 2020-2023  润新知