• ibevent 定制——libevent 定制内存分配


    libevent 定制内存分配

    默认情况下,libevent 使用 C 库的内存管理函数在堆上分配内存。通过提供 mallocreallocfree 的替代函数,可以让 libevent 使用其他的内存管理器。希望 libevent 使用一个更高效的分配器时;或者希望 libevent 使用一个工具分配器,以便检查内存泄漏时,可能需要这样做。

    libevent允许用户(库的使用者)定制自己的内存分配函数。

    首先,如果要定制自己的内存分配函数,就得在一开始配置编译libevent库是,不能加入--disable-malloc-replacement选项。默认情况下,是没有这个选项的。如果加入了这个选项,那么将会在生成的event-config.h中,定义_EVENT_DISABLE_MM_REPLACEMENT这个宏。下面是libevent内存分配函数的声明(在mm-internal.h文件):

    /*
     * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     * 1. Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     * 2. Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     * 3. The name of the author may not be used to endorse or promote products
     *    derived from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    #ifndef MM_INTERNAL_H_INCLUDED_
    #define MM_INTERNAL_H_INCLUDED_
    
    #include 
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #ifndef EVENT__DISABLE_MM_REPLACEMENT
    /* Internal use only: Memory allocation functions. We give them nice short
     * mm_names for our own use, but make sure that the symbols have longer names
     * so they don't conflict with other libraries (like, say, libmm). */
    
    /** Allocate uninitialized memory.
     *
     * @return On success, return a pointer to sz newly allocated bytes.
     *     On failure, set errno to ENOMEM and return NULL.
     *     If the argument sz is 0, simply return NULL.
     */
    EVENT2_EXPORT_SYMBOL
    void *event_mm_malloc_(size_t sz);
    
    /** Allocate memory initialized to zero.
     *
     * @return On success, return a pointer to (count * size) newly allocated
     *     bytes, initialized to zero.
     *     On failure, or if the product would result in an integer overflow,
     *     set errno to ENOMEM and return NULL.
     *     If either arguments are 0, simply return NULL.
     */
    EVENT2_EXPORT_SYMBOL
    void *event_mm_calloc_(size_t count, size_t size);
    
    /** Duplicate a string.
     *
     * @return On success, return a pointer to a newly allocated duplicate
     *     of a string.
     *     Set errno to ENOMEM and return NULL if a memory allocation error
     *     occurs (or would occur) in the process.
     *     If the argument str is NULL, set errno to EINVAL and return NULL.
     */
    EVENT2_EXPORT_SYMBOL
    char *event_mm_strdup_(const char *str);
    
    EVENT2_EXPORT_SYMBOL
    void *event_mm_realloc_(void *p, size_t sz);
    EVENT2_EXPORT_SYMBOL
    void event_mm_free_(void *p);
    #define mm_malloc(sz) event_mm_malloc_(sz)
    #define mm_calloc(count, size) event_mm_calloc_((count), (size))
    #define mm_strdup(s) event_mm_strdup_(s)
    #define mm_realloc(p, sz) event_mm_realloc_((p), (sz))
    #define mm_free(p) event_mm_free_(p)
    #else
    #define mm_malloc(sz) malloc(sz)
    #define mm_calloc(n, sz) calloc((n), (sz))
    #define mm_strdup(s) strdup(s)
    #define mm_realloc(p, sz) realloc((p), (sz))
    #define mm_free(p) free(p)
    #endif
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    这些内存分配函数是给libevent使用的,而非用户(从这些接口声明在mm-internal.h文件中就可以看到这一点)。libevent的其他函数要申请内存就调用mm_malloc之类的宏定义。如果一开始在配置的时候(event-config.h)就禁止用户定制自己的内存分配函数,那么就把这些宏定义为C语言标准内存分配函数。
    当然,即使没有禁止,如果用户没有定制自己的内存分配函数,最终还是调用C语言的标准内存分配函数。这一点在event_mm_xxxx这些函数的实现上可以看到。
    定制内存函数的声明在include/event2/event.h:

    #if !defined(EVENT__DISABLE_MM_REPLACEMENT) || defined(EVENT_IN_DOXYGEN_)
    /**
     Override the functions that Libevent uses for memory management.
    
     Usually, Libevent uses the standard libc functions malloc, realloc, and
     free to allocate memory.  Passing replacements for those functions to
     event_set_mem_functions() overrides this behavior.
    
     Note that all memory returned from Libevent will be allocated by the
     replacement functions rather than by malloc() and realloc().  Thus, if you
     have replaced those functions, it will not be appropriate to free() memory
     that you get from Libevent.  Instead, you must use the free_fn replacement
     that you provided.
    
     Note also that if you are going to call this function, you should do so
     before any call to any Libevent function that does allocation.
     Otherwise, those functions will allocate their memory using malloc(), but
     then later free it using your provided free_fn.
    
     @param malloc_fn A replacement for malloc.
     @param realloc_fn A replacement for realloc
     @param free_fn A replacement for free.
     **/
    EVENT2_EXPORT_SYMBOL
    void event_set_mem_functions(
    	void *(*malloc_fn)(size_t sz),
    	void *(*realloc_fn)(void *ptr, size_t sz),
    	void (*free_fn)(void *ptr));
    /** This definition is present if Libevent was built with support for
        event_set_mem_functions() */
    #define EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    其定义在event.c中:

    void
    event_set_mem_functions(void *(*malloc_fn)(size_t sz),
    			void *(*realloc_fn)(void *ptr, size_t sz),
    			void (*free_fn)(void *ptr))
    {
    	mm_malloc_fn_ = malloc_fn;
    	mm_realloc_fn_ = realloc_fn;
    	mm_free_fn_ = free_fn;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    定制自己的内存分配函数需要注意的一些地方:

    • 替换内存管理函数影响libevent 随后的所有分配、调整大小和释放内存操作。所以必须保证在调用任何其他libevent函数之前进行定制。否则,libevent可能用定制的free函数释放C语言 库的malloc函数分配的内存
    • mallocrealloc函数返回的内存块应该具有和C库返回的内存块一样的地址对齐
    • realloc函数应该正确处理realloc(NULL, sz)(也就是当作malloc(sz)处理)
    • realloc函数应该正确处理realloc(ptr, 0)(也就是当作free(ptr)处理)
    • 你的 free 函数不必处理 free(NULL)
    • 你的 malloc 函数不必处理 malloc(0)
    • 如果在多个线程中使用libevent,替代的内存管理函数需要是线程安全的
    • 如果要释放由libevent函数分配的内存,并且已经定制了mallocrealloc函数,那么就应该使用定制的free函数释放。否则将会C语言标准库的free函数释放定制内存分配函数分配的内存,这将发生错误。所以三者要么全部不定制,要么全部定制。
  • 相关阅读:
    java计算机毕业设计猫咪伤患会诊复查医疗平台源码+系统+mysql数据库+lw文档
    WebGL编程指南-23 光照原理、漫反射光计算、漫反射光照射下的立方体
    【C语言】进阶——结构体+枚举+联合
    软件定义存储不能打?这家成立刚三年的公司问鼎全球存储性能榜
    uni-app : 生成三位随机数、自定义全局变量、自定义全局函数、传参、多参数返回值
    2022年 PHP面试问题记录
    Linux——echo命令,管道符,vi/vim 文本编辑器
    数据库主从切换过程中Druid没法获取连接错误
    基本算法模板整理——链表,二叉树,快速排序
    抽象工厂模式-C++实现
  • 原文地址:https://blog.csdn.net/cclethe/article/details/133002842