第一季度
在一些开放源代码库中,有一种保存私有缓冲区的通用模式:
/* ======== 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_key
和pthread_once
。但是有些嵌入式环境没有它们的内置实现,对于非线程程序来说,这种方法看起来很简单,也不好看。有没有其他简单和干净的选择来处理这个问题?问题2
libc也有类似的行为。
我写了一个简单的libc函数测试代码,这使得valgrind报告在我的
strftime()
上肯定丢失了一些。(编译器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版本?
最佳答案
在第一种情况下,程序退出时内存泄漏是正确的,但它是一次性分配一个小(256字节)块内存。它只应“可能丢失”,因为仍有指向分配空间的指针。如果这是最严重的泄漏,你做得很好,你可以写一个抑制它。
在第二个场景中,您的代码名义上调用了strftime()
,但运行时却说调用了strftime_l()
,可能是使用null作为区域设置指针。不太清楚这是否无害;为什么会失去两个直接和两个间接的街区?可能值得在一个循环中调用strftime()
几次,看看问题的严重性。如果它保持不变,那就不值得担心了。如果泄漏量增加,那么你可能发现了一个漏洞。也许10.9.1会解决这个问题(必须重新启动!)。没有cleanup_strftime()
函数;不应该需要函数。
可能的损失也是一个麻烦。我去看看。您可以为内存创建抑制,这样您的代码看起来运行得很干净(就像运行时系统所允许的那样)。但这是不可取的。
关于c - 如何管理模块特定的指针,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20625780/