• 沉淀之log4c的malloc


        内存分配函数的接口,log4c内部又重新的封装了一下,在内部实现上仍然是采用的系统内存分配的那一套调用接口。重新实现这么一套接口,应该是为了方便调试,保证易用性和稳定下有了提高。
        这个封装的内部在分配了之后对于返回值做了检查。

    malloc.h
    1. #ifndef __sd_malloc_h
    2. #define __sd_malloc_h
    3. #include <stddef.h>
    4. #include <stdlib.h>
    5. #include "defs.h"
    6. /**
    7. * @file malloc.h
    8. */
    9. __SD_BEGIN_DECLS
    10. typedef void (*sd_malloc_handler_t)();
    11. extern sd_malloc_handler_t sd_malloc_set_handler(void (*a_handler)());
    12. #ifndef __SD_DEBUG__
    13. extern void *sd_malloc(size_t n);
    14. extern void *sd_calloc(size_t n, size_t s);
    15. extern void *sd_realloc(void *p, size_t n);
    16. extern char *sd_strdup (const char *__str);
    17. #else
    18. #define sd_malloc malloc
    19. #define sd_calloc calloc
    20. #define sd_realloc realloc
    21. #define sd_strdup strdup
    22. #endif
    23. __SD_END_DECLS
    24. #endif
        头文件中一样包含着一对__SD_BEGIN_DECLS和__SD_END_DECLS,以及头文件defs.h的包含。
    使用typedef定义了一个函数类型:typedef void (*sd_malloc_handler_t)();    标识sd_malloc_handler_t代表一个函数类型,
    用这个类型可以定义类似如下结构的函数变量:
        void test()
    然后是根据一个宏:__SD_DEBUG__作为编译开关进行选择两套内存申请函数,一个是用宏进行定义的接口,实际就是系统本身的内存操作接口。另一个是自行实现的一组函数:sd_malloc、sd_calloc、sd_realloc、sd_strdup。

    malloc.c里面就是对于在debug模式下的时候所实现的头文件中声明的这一组函数。

    malloc.c
    1. #ifdef HAVE_CONFIG_H
    2. #include "config.h"
    3. #endif
    4. #include <stdio.h>
    5. #ifdef HAVE_UNISTD_H
    6. #include <unistd.h>
    7. #endif
    8. #include <string.h>
    9. #include <stdlib.h>
    10. #include "error.h"
    11. #if defined(__APPLE__)
    12. # include <sys/time.h>
    13. # include <crt_externs.h>
    14. # define environ (*_NSGetEnviron())
    15. #endif /* __APPLE__ */
    16. typedef void (*sd_malloc_handler_t)();
    17. static sd_malloc_handler_t handler = NULL;
    18. static void *
    19. fixup_null_alloc (n)
    20. size_t n;
    21. {
    22. void* p = 0;
    23. #ifdef HAVE_SBRK
    24. static char* first_break = NULL;
    25. if (n == 0)
    26. p = malloc ((size_t) 1);
    27. if (p == 0) {
    28. extern char **environ;
    29. size_t allocated;
    30. if (first_break != NULL)
    31. allocated = (char *) sbrk (0) - first_break;
    32. else
    33. allocated = (char *) sbrk (0) - (char *) &environ;
    34. sd_error(" Cannot allocate %lu bytes after allocating %lu bytes ",
    35. (unsigned long) n, (unsigned long) allocated);
    36. if (handler)
    37. handler();
    38. else {
    39. sd_error(" Memory exhausted !! Aborting. ");
    40. abort();
    41. }
    42. }
    43. #endif
    44. return p;
    45. }
    46. sd_malloc_handler_t
    47. sd_malloc_set_handler(a_handler)
    48. sd_malloc_handler_t a_handler;
    49. {
    50. sd_malloc_handler_t previous = handler;
    51. handler = a_handler;
    52. return previous;
    53. }
    54. /* Allocate N bytes of memory dynamically, with error checking. */
    55. void *
    56. sd_malloc (n)
    57. size_t n;
    58. {
    59. void *p;
    60. p = malloc (n);
    61. if (p == 0)
    62. p = fixup_null_alloc (n);
    63. return p;
    64. }
    65. /* Allocate memory for N elements of S bytes, with error checking. */
    66. void *
    67. sd_calloc (n, s)
    68. size_t n, s;
    69. {
    70. void *p;
    71. p = calloc (n, s);
    72. if (p == 0)
    73. p = fixup_null_alloc (n * s);
    74. return p;
    75. }
    76. /* Change the size of an allocated block of memory P to N bytes,
    77. with error checking.
    78. If P is NULL, run sd_malloc. */
    79. void *
    80. sd_realloc (p, n)
    81. void *p;
    82. size_t n;
    83. {
    84. if (p == 0)
    85. return sd_malloc (n);
    86. p = realloc (p, n);
    87. if (p == 0)
    88. p = fixup_null_alloc (n);
    89. return p;
    90. }
    91. /* Return a newly allocated copy of STRING. */
    92. char *
    93. sd_strdup (string)
    94. const char *string;
    95. {
    96. return strcpy (sd_malloc (strlen (string) + 1), string);
    97. }


        其实每个函数的实现里面,都是先调用系统函数进行内存分配,当内存分配不成功的时候会调用fixup_null_alloc函数进行再次尝试。熟悉了ansi C的同学看着这里的函数的定义会觉得比较怪异,其实Ansi C之前的函数形式就是这样的(K&R C风格),Ansi C为了兼容性也实现支持这种格式。参数还需要再这里重新定义下;
        然后对于fixup_null_alloc的实现着重的研究下,因为下面所有函数的实现在失败的时候都会去调用这个函数,然后另外还有一个函数就是sd_malloc_set_handler,我在log4c里面搜索了一下,这个函数没有被调用的地方,也没有文字性的说明,搞不懂到底是要做什么,所以暂时不进行分析。

        fixup_null_alloc函数的定义在上面的第二十五行到第五十六行。其中第二十八行到三十五行在传入参数为0的时候做了一次判断并根据判断进行调用系统函数进行内存的分配。接下来的三十六行到五十三行是利用sbrk系统调用获取而这里参数给的是0,可以利用这个调用获取当前program break的位置。然后进行计算,打印一下当前系统中内存的情况进行报错处理。
        至于为什么用sbrk (0) - first_break;或者用sbrk (0) - (char *) &environ;
        首先使用sbrk (0)能够知道当前系统中可用堆的结束的位置,然后static关键字声明的first_break在bss段的最后,两者相减就能得到一共有多少内存已经分配出去了。至于environ为什么,还没有理解。

        至于使用方式上就拿这一组当成系统的内存操作接口就可以了。示例程序就不啰嗦了。

        











  • 相关阅读:
    编程实践56
    诫子篇
    编程实践58
    编程实践55
    C#Process类应该声明个什么引用空间啊 找不到类型或命名空间名称“Process”(是否缺少 using 指令或程序集引用?) 如何解决?
    课堂题目54
    jQuery学习笔记jQuery的动画
    Asp.net生成各种网页快捷方式[转贴]
    jQuery学习笔记Helloworld
    FreeTextBox配置
  • 原文地址:https://www.cnblogs.com/cfzhang/p/03c1c19c4d9a8e0a667f52da67bcd1cd.html
Copyright © 2020-2023  润新知