【问题标题】:how to manage module specific pointers如何管理模块特定的指针
【发布时间】:2013-12-17 04:11:03
【问题描述】:

第一季度

在一些开源库中,有一种常见的模式来保存私有缓冲区:

/* ======== in modnamemapping.c ======== */
static char *private_buffer = NULL;
const char *getname( int id ) {
  if ( !private_buffer )
    private_buffer = (char *) malloc( 0x100 ); // in addition, the length may not
                                               // a compile-period-constant, or
                                               // here is some realloc() and the
                                               // branch does not enter only once.
  snprintf( private_buffer, 0x100, "NameOf%d", id );
  return private_buffer;
}
// *NO* code to free private_buffer ...

据我所知,这应该会导致内存泄漏,是吗?

我只知道解决此问题的一种方法,即使用pthread_keypthread_once。但是有一些嵌入式环境没有它们的内置实现,这种方法对于非线程程序来说看起来微不足道且不漂亮。还有其他 simpleclean 选择来处理这个问题吗?

第二季度

libc 中有类似的行为。 我写了一个 libc 函数strftime() 的简单测试代码,这使得 valgrind 在我的OS X Mavericks 上报告一些肯定丢失。 (brew 中的编译器 apple-gcc42 版本 4.2.1-5666.3)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main( void ) {
    char buf[0x40], *fmt = "%x %X";
    time_t t1 = time( NULL );
    struct tm t2;
    int ret;
    (void) localtime_r( &t1, &t2 );
    ret = strftime( buf, sizeof(buf), fmt, &t2 );
    printf( "strftime('%s', <now>) = %d: [%s]\n", fmt, ret, buf );
    return 0;
}

绝对丢失的一个:

==46746== 2,242 (16 direct, 2,226 indirect) bytes in 1 blocks are definitely lost in loss record 83 of 87
==46746==    at 0x70AB: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==46746==    by 0x334FE6: _nc_table_new (in /usr/lib/system/libsystem_notify.dylib)
==46746==    by 0x334A63: __token_table_add_block_invoke (in /usr/lib/system/libsystem_notify.dylib)
==46746==    by 0xB62AC: _dispatch_client_callout (in /usr/lib/system/libdispatch.dylib)
==46746==    by 0xB621B: dispatch_once_f (in /usr/lib/system/libdispatch.dylib)
==46746==    by 0x3328A6: token_table_add (in /usr/lib/system/libsystem_notify.dylib)
==46746==    by 0x3326B2: notify_register_check (in /usr/lib/system/libsystem_notify.dylib)
==46746==    by 0x196AB5: notify_register_tz (in /usr/lib/system/libsystem_c.dylib)
==46746==    by 0x1965EA: tzsetwall_basic (in /usr/lib/system/libsystem_c.dylib)
==46746==    by 0x1967A7: _st_tzset_basic (in /usr/lib/system/libsystem_c.dylib)
==46746==    by 0x198FAE: strftime_l (in /usr/lib/system/libsystem_c.dylib)
==46746==    by 0x100000EB2: main (strftime.c:10)

总结:

==46746== LEAK SUMMARY:
==46746==    definitely lost: 32 bytes in 2 blocks
==46746==    indirectly lost: 4,298 bytes in 7 blocks
==46746==      possibly lost: 10,808 bytes in 1 blocks
==46746==    still reachable: 16,384 bytes in 1 blocks
==46746==         suppressed: 25,272 bytes in 375 blocks

在程序退出之前是否应该调用 libc 中的 cleanup-strftime 函数?或者一个新的 libc 补丁?

【问题讨论】:

标签: c gcc memory-leaks osx-mavericks libc


【解决方案1】:

在第一种情况下,程序退出时内存泄漏是正确的,但它是一次性分配一小块(256 字节)内存。它应该只“可能丢失”,因为仍然有一个指向分配空间的指针。如果这是你遇到的最严重的泄漏,那么你做得很好,你可以为它写一个抑制。

在第二种情况下,您的代码名义上调用strftime(),但运行时说strftime_l() 被调用,大概是使用null 作为语言环境指针。尚不清楚这是无害的。为什么会丢失两个直接块和两个间接块?可能值得在循环中调用strftime() 几次以查看问题的严重程度。如果它保持不变,那么它可能不值得担心。如果泄漏量增加,那么您可能已经发现了一个错误。也许 10.9.1 会解决这个问题(必须重新启动!)。没有cleanup_strftime() 函数;应该不需要。

可能丢失也很麻烦。我会检查一下。您可能能够为内存创建抑制,因此您的代码看起来运行干净(运行时系统允许的干净)。但这是不可取的。

【讨论】:

    【解决方案2】:

    Q1 是某种内存泄漏。总有:

    static char private_buffer[0x100];
    

    并删除分配代码。这适用于某些环境,但不是全部(例如 ROPI 代码)。在这种情况下,真正的修复是修复getname的定义:

    const char *getname( int id, char* buf, size_t len ) {
      if (buf)
         snprintf( buf, len, "NameOf%d", id );
      return buf;
    }
    

    但这意味着还要修复所有getname 的调用者,这可能不够简单和干净。

    对于 Q2,strftime 没有清理功能。正如 Jonathan Leffler 建议的那样,这可能值得调查。底层库函数经常“泄漏”,但通常不是问题。

    【讨论】:

      猜你喜欢
      • 2014-02-24
      • 2012-01-14
      • 1970-01-01
      • 2017-05-14
      • 2013-01-05
      • 2013-04-25
      • 2017-06-13
      • 2015-05-19
      • 2020-01-02
      相关资源
      最近更新 更多