影响GC顺序(保持对象存活)

时间:2015-04-10 14:16:52

标签: c# memory-management garbage-collection

以下情况:我有一个单例类,它在内部加载一个C-DLL(让它称之为Foo),并且还构造访问相同DLL的元素(也在d& #39; tor) - 它的名字应该是Bar。

现在的问题是:当我关闭应用程序时,GC有时会在所有创建的Bar实例被销毁之前销毁Foo。结果是不可取的:Foo是一个很好的类,它自己清理,包括关闭DLL。 Bar需要在关闭时访问DLL函数 - 导致访问冲突。

所以问题是:如何解决这个问题?我最初的方法是:由于Foo正在创建所有Bar实例,只需将每个创建的Bar实例放入List(它是Foo的一个成员)来创建一些引用,这个想法很明显:GC可能在销毁对象之前销毁所有引用抱着它。不幸的是,情况并非如此(可能是因为可能的循环引用)也许有一些强大的参考可以强制这种行为。

所以...任何想法?

附录:

使用IDisposeable的想法似乎很棒。我想到一个特殊问题:我不想在Bartry块中封装创建的using对象(因为我想让它可用于多个独立的函数) 。 所以我的方法是仍然跟踪Bar单例中创建的Foo对象,并为Dispose析构函数上的每个Bar调用Foo,以及在每个Bar析构函数上单独调用它。在我的特定实现中,这看起来很好,因为我确保只调用一次功能(因此Bar首先被破坏然后它就可以了Foo仍在上升,或者Bar最后被破坏,那么关键功能将不再被调用)。 仍然......这种方法看起来不是很干净,让我们看看下面的例子:

Bar bar = null;

void Func1()
{
  if(bar == null) bar = Foo.Instance.CreateBar();
  bar.DoSomething();
}

void Func2()
{
  if(bar == null) bar = Foo.Instance.CreateBar();
  bar.Dispose();
}

如果我只调用Func1这个罚款。但是......在调用Func1后调用Func2可能会导致问题(因为DoSomething要求不处置该对象)。当然:我仍然可以添加一些安全检查,但不知怎的,这对我来说似乎并不干净。

有没有更好的做法?

关于用例可能还有一点:这是库(实际是DLL包装器)的所有部分,其中我有一个Singleton(它保存对DLL的访问权限),用于创建特定对象。这些对象在DLL中使用句柄。为了使用户体验受益,我决定不向用户公开句柄,而是向特定的类公开(这是在内部保留句柄,然后使用更直接)。

所以而不是

uint handle = Foo.Instance.CreateObject();
Foo.Instance.DoSomething(handle);
Foo.Instance.Destroy(handle);

我有s.th.像:

Bar bar = Foo.Instance.CreateBar();
bar.DoSomething();
//I don't want the user to care about destruction, which is actually causing my initial problem

也许这种架构存在缺陷,但老实说,我无法想到更好的方法(实际上,我认为这是一个很好的架构)

1 个答案:

答案 0 :(得分:3)

你正试图解决CLR拒绝解决的问题,强烈暗示即将出现的麻烦。终结顺序是非确定性的,你也不能强迫它。你必须引用自己来计算什么时候没有剩余的Foo或Bar对象。在它们的构造函数中递增它,在它们的终结器中递减它,在它达到0时进行清理。

请注意,这确实意味着清理代码不能成为Foo的一部分,或者必须是静态的,因为它可能是一个Bar,它将引用计数减少到0。

注意“颠簸”,客户端代码反复创建一个Foo并让它再次死亡,你将不断加载和卸载DLL。也许留下DLL驻留并不是那么糟糕:) pinvoke管道当然不认为它。