2

当我尝试删除 leveldb 实例时,我得到了一些非常烦人的断言,但我不确定它为什么会发生!

断言发生在version_set.cc文件中:

void VersionSet::AppendVersion(Version* v) {
  // Make "v" current
  assert(v->refs_ == 0); // <---??? how do I avoid this assertion?
  // the rest of the source code is available in the link to version_set.cc
}

此外,它在同一文件的另一个位置断言:

Version::~Version() {
  assert(refs_ == 0); // <-- Again... how do I avoid this one too?
  // the rest of the source code is available in the link to version_set.cc
}

这是有关我系统中使用情况的更多背景详细信息,我有一个:

  • ExtStorage具有LevelDB::DB实例的类(扩展存储)。
  • class EextStorageDotNet,它是ExtStorage.
  • class AltStorage,它包含一个指向 ExtStorage 类的指针(通过构造函数传递):
  • class AltStorageDotNet,它是AltStorage.

备用存储类如下所示:

class AltStorage{
    ExtStorage* instance;
public:
    AltStorage(ExtStorage* extStorage):instance(extStorage){}

    ~AltStorage(){
        delete instance;
        instance = NULL;
    }
};

该类ExtStorage如下所示:

class ExtStorage{
    leveldb::DB* mydb;
public:
    ExtStorage(/*some parameters*/){
         mydb = new leveldb::DB(/*parameters*/);
    }

    // Destructor
    ~ExtStorage() {
        Close();
    }

    // deletes the leveldb::DB instance
    void Close() {
        if(mydb == NULL) {
            delete mydb; // <-- Asserts every time I get here when using with the AltStorageDotNet
            mydb= NULL;

            // Close the L1 and L2 caches
            // only once (
        }
    }
}

该类AltStorageDotNet如下所示:

public ref class AltStorageDotNet{
    AltStorage* altInstance;
    ExtStorageDotNet^ extInstance;
public:
    AltStorageDotNet() {
        ExtStorage extStorage = new ExtStorage(/*params*/);
        altInstance = new AltStorage(extStorage);
        extInstance = gcnew ExtStorageDotNet(extStorage);
    }

    ~AltStorageDotNet(){
        delete altInstance;
        altInstance = NULL;
        // no need to delete extInstance since it was created with gcnew 
    }

    !AltStorageDotNet(){
        delete altInstance;
        altInstance = NULL;
        // no need to delete extInstance since it was created with gcnew
    }

    inline ExtStorageDotNet^ GetExtInstance(){return extInstance;}
};

DotNet 包装器如下所示:

public ref class ExtStorageDotNet{
private:
    ExtStorage* instance;
public:
    ExtStorageDotNet(ExtStorage* extStorage){
        instance = extStorage;
    }

    ~ExtStorageDotNet(){
        delete instance;
        instance = NULL;
    }

    !ExtStorageDotNet(){
        delete instance;
        instance = NULL;
    }

    void Close(){instance->Close();}
};

每当我ExtStorageDotNet在我的 C# 应用程序中使用包装器时,一切正常,并且没有断言。但是,当我使用AltStorageDotNet包装器并访问ExtStorageDotNet包装器时,我会在关闭数据库时获得断言。这是测试套件的所有部分,我在其中为每个测试用例初始化一个实例并在每个测试用例之后关闭它;在新的测试用例开始之前,相关的数据库文件会被删除。我看不出它应该发生的任何原因,并且断言对追踪问题没有帮助。

4

2 回答 2

2

我摆脱了嵌套引用,但这并没有解决问题。事实证明,导致这个问题的问题并不是我所看到的。当用户获取数据库的迭代器并且在删除数据库之前未能删除迭代器时,就会出现此问题。这在与级别 db 相关的谷歌小组中进行了讨论。

// Caller should delete the iterator when it is no longer needed.
// The returned iterator should be deleted before this db is deleted.
virtual Iterator* NewIterator(const ReadOptions& options) = 0; 

当用户获得迭代器时,他们应该在删除数据库之前将其删除,否则他们将获得上述断言。

于 2011-10-03T21:25:42.767 回答
1

我不知道它是否与您的断言有关,但此代码肯定会导致内存损坏。ExtStorageDotNet和都是AltStorageDotNet一次性的和可终结的,并且都(直接或间接地)delete实例ExtStorage——总是,一个会delete在另一个已经拥有的实例之后。

另外,正如我在评论中所说,您的代码中的评论no need to delete extInstance since it was created with gcnew已经过时了——有关详细信息,请参阅此答案。(我假设您了解 C# 并因此了解IDisposable;如果您不了解,那么您真的需要阅读一些内容。)

于 2011-08-17T23:31:38.510 回答