我应该在调用DB->在数据上放置DB_DBT_MALLOC标志后解除分配数据吗?

时间:2012-12-03 14:54:28

标签: c memory-management berkeley-db

我在调用DB-> put()后释放内存有问题。 当我这样做时,它会说“双重免费或腐败”。

代码示例:

DBT key,value;
int err;
...
memset(value,0,sizeof(DBT));
value.data=malloc(10);
memset(value.data,10);
value.flags=DB_DBT_MALLOC;
...
value.size=10;
...
if((err=db->put(db,NULL,&key,&value,0))){
    ...
}
free(value.data);

C API参考不包含有关该主题的任何信息,它仅提供有关在检索(但不存储)数据时使用DB_DBT_MALLOC的一些信息:

  

设置此标志后,Berkeley DB将为返回的键或数据项(使用malloc(3)或用户指定的malloc函数)分配内存,并在键的数据字段中返回指向它的指针或数据DBT结构。因为任何分配的内存成为调用应用程序的责任,调用者必须确定是否使用数据字段的返回值分配内存。

当调用DB-> put时,Berkeley DB不会返回任何数据,它只存储一个键/数据对。是否复制数据,或者在调用DB-> close或ENV->关闭之前存储器是否应该存在?

1 个答案:

答案 0 :(得分:1)

DB_DBT_MALLOCdb->put()无效,因为db->put()会复制数据。所以你最有可能在其他地方破坏你的堆。这种错误并不总是表现在它们造成的地方。我的猜测是你正在写一些缓冲区的结尾。尝试在其上运行Valgrind,跟踪这类问题通常非常有用。

我运行了这个简单的测试程序,它运行得很好,valgrind报告没有泄漏:

void test() {
    DB *DB;
    DBT key;
    DBT data;
    DBT value;
    int i;

    db_create(&DB, NULL, 0); 
    if(DB->open(DB, NULL, "tmp.db2", NULL, DB_BTREE, DB_CREATE, 0664) != 0) {
        printf("DB->open failed!\n");
        exit(0);
    }

    memset(&value,0,sizeof(value));
    value.size=10;
    value.data=malloc(value.size);
    memset(&key,0,sizeof(key));
    key.data=malloc(sizeof(unsigned int));
    key.size = sizeof(unsigned int);    
    for(i=0; i < 10; i++) {
        *(unsigned int*)key.data = i;
            memset(value.data, 0, value.size); /* valgrind complains if I leave this out? */
        sprintf(value.data, "test %d", i);

        if(DB->put(DB, NULL, &key, &value, 0 ) != 0) {
            printf("key stored failed\n");
            exit(-1);
        }
    }
    free(value.data);
    free(key.data);

    key.data = malloc(sizeof(unsigned int));
    key.size = sizeof(unsigned int); 
    *(unsigned int*)key.data=5;
    memset(&data,0,sizeof(data));
    data.flags = DB_DBT_MALLOC;
    DB->get(DB, NULL, &key,&data, 0);

    printf("size: %d data: %s\n", data.size, (const char*)data.data);
    DB->close(DB, 0);
    free(data.data);
    free(key.data);

    return;
}