• Blender内存管理库(bf_intern_guardedalloc)


    Blender内部定义了自己内存泄漏检测机制,同时提供了了二套实现机制,函数整合于于bf_intern_guardedalloc库中:

    mallocn_lockfree_impl.c和mallocn_guarded_impl.c分别实现了这二套内存分配机制,头文件定义于MEM_guardedalloc.h中,为方便实现二种机制的切换,函数头使用的是函数指针方式,以便于动态切换。

    mallocn_lockfree_impl.c中的实现用于正常工作模式,mallocn_guarded_impl.c的实现用于调试模式,提供更多信息,更方便定位内存问题。

    mallocn.c中实现函数指针被赋值,默认使用mallocn_lockfree_impl.c中的函数,如果需要使用mallocn_guarded_impl.c中的函数,只需要调用MEM_use_guarded_allocator函数,实现二套机制的切换。

    在blender主程序文件中createor.c中,只有当明确指明调试模式时使用guarded模式内存分配,以方便理准确定位内存问题

     1 /* NOTE: Special exception for guarded allocator type switch:
     2    *       we need to perform switch from lock-free to fully
     3    *       guarded allocator before any allocation happened.
     4    */
     5   {
     6     int i;
     7     for (i = 0; i < argc; i++) {
     8       if (STR_ELEM(argv[i], "-d", "--debug", "--debug-memory", "--debug-all")) {
     9         printf("Switching to fully guarded memory allocator.
    ");
    10         MEM_use_guarded_allocator();
    11         break;
    12       }
    13       else if (STREQ(argv[i], "--")) {
    14         break;
    15       }
    16     }
    17     MEM_initialize_memleak_detection();
    18   }

     同时在第17行调用MEM_initialize_memleak_detection()函数实例化MemLeakPrinter(leak_detector.cc中定义)类到静态变量中,用于初始内存泄漏检测。该类只定义了析构函数,因此在程序结束时自动释放时调用析构函数,实现打印内存泄漏信息。也就无需主动调用,正发布版程序中也无需处理,不用担心性能。

    例如:MEM_guardedalloc.h中定义的函数指针:extern void *(*MEM_callocN)(size_t len, const char *str) ,在mallocn.c中将它赋值

    void *(*MEM_callocN)(size_t len, const char *str) = MEM_guarded_callocN;

    MME_lockfree_callocN函数定义于mallocn_guarded_impl.c文件中,如下: 

     1 void *MEM_guarded_mallocN(size_t len, const char *str)
     2 {
     3   MemHead *memh;
     4 
     5   len = SIZET_ALIGN_4(len);
     6 
     7   memh = (MemHead *)malloc(len + sizeof(MemHead) + sizeof(MemTail));
     8 
     9   if (LIKELY(memh)) {
    10     make_memhead_header(memh, len, str);
    11     if (UNLIKELY(malloc_debug_memset && len)) {
    12       memset(memh + 1, 255, len);
    13     }
    14 
    15 #ifdef DEBUG_MEMCOUNTER
    16     if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL)
    17       memcount_raise(__func__);
    18     memh->_count = _mallocn_count++;
    19 #endif
    20     return (++memh);
    21   }
    22   print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u
    ",
    23               SIZET_ARG(len),
    24               str,
    25               (unsigned int)mem_in_use);
    26   return NULL;
    27 }

    通过代码分析可知,内存分配的保护措施就是,在请求分配内存块时,在前面额外增加了一个MemHead和MemTail,它存储了请求的内存块大小,同时更新totblock,mem_in_use,peak_mem三个与内存保护相关变量

    以下是Mem_freeN指向的函数MEM_gurded_freeN(它与Mem_allocN相对应,用于释放内存)

    
    
     1 void MEM_guarded_freeN(void *vmemh)
     2 {
     3   MemTail *memt;
     4   MemHead *memh = vmemh;
     5   const char *name;
     6 
     7   if (memh == NULL) {
     8     MemorY_ErroR("free", "attempt to free NULL pointer");
     9     /* print_error(err_stream, "%d
    ", (memh+4000)->tag1); */
    10     return;
    11   }
    12 
    13   if (sizeof(intptr_t) == 8) {
    14     if (((intptr_t)memh) & 0x7) {
    15       MemorY_ErroR("free", "attempt to free illegal pointer");
    16       return;
    17     }
    18   }
    19   else {
    20     if (((intptr_t)memh) & 0x3) {
    21       MemorY_ErroR("free", "attempt to free illegal pointer");
    22       return;
    23     }
    24   }
    25 
    26   memh--;
    27   if (memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) {
    28     MemorY_ErroR(memh->name, "double free");
    29     return;
    30   }
    31 
    32   if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) {
    33     memt = (MemTail *)(((char *)memh) + sizeof(MemHead) + memh->len);
    34     if (memt->tag3 == MEMTAG3) {
    35 
    36       if (leak_detector_has_run) {
    37         MemorY_ErroR(memh->name, free_after_leak_detection_message);
    38       }
    39 
    40       memh->tag1 = MEMFREE;
    41       memh->tag2 = MEMFREE;
    42       memt->tag3 = MEMFREE;
    43       /* after tags !!! */
    44       rem_memblock(memh);
    45 
    46       return;
    47     }
    48     MemorY_ErroR(memh->name, "end corrupt");
    49     name = check_memlist(memh);
    50     if (name != NULL) {
    51       if (name != memh->name) {
    52         MemorY_ErroR(name, "is also corrupt");
    53       }
    54     }
    55   }
    56   else {
    57     mem_lock_thread();
    58     name = check_memlist(memh);
    59     mem_unlock_thread();
    60     if (name == NULL) {
    61       MemorY_ErroR("free", "pointer not in memlist");
    62     }
    63     else {
    64       MemorY_ErroR(name, "error in header");
    65     }
    66   }
    67 
    68   totblock--;
    69   /* here a DUMP should happen */
    70 }
    
    
    
    只要通过该库中函数分配的内存就能通过设置启动参数,在程序结束时显示内存泄漏等相关情况。
  • 相关阅读:
    Postman使用教程
    CAD和ArcGIS转换 矢量配准
    SAP CRM Advanced search和Simple search里Max hit表现行为的差异
    SAP CRM Product simple search的启用步骤
    如何快速定位SAP CRM订单应用(Order Application)错误消息抛出的准确位置
    如何动态修改SAP CRM WebClient UI表格栏的宽度
    如何在SAP CRM WebClient UI里创建web service并使用ABAP消费
    如何处理SAP CRM Web Service错误
    如何使用SAP CRM WebClient UI实现一个类似新浪微博的字数统计器
    如何开启SAP CRM基于WORD模板创建附件的功能
  • 原文地址:https://www.cnblogs.com/jiaping/p/8093304.html
Copyright © 2020-2023  润新知