我正在尝试为我正在编写的小爱好游戏编写一个简单的资源管理器。此资源管理器需要执行的任务之一是卸载未使用的资源。我可以考虑通过两种方式做到这一点:
当一个对象不再需要对资源的引用时,它必须调用资源管理器的一个方法来表示它不再使用它;或者
当对象不再需要对资源的引用时,它只需将其设置为 null。然后,当要求资源管理器卸载未使用的资源时,它会获取每个资源的引用计数(通过反射?)。如果引用计数为 1(资源管理器将引用该资源),则卸载该资源。
有没有办法在 C# 中实现第二个解决方案?谢谢。
我正在尝试为我正在编写的小爱好游戏编写一个简单的资源管理器。此资源管理器需要执行的任务之一是卸载未使用的资源。我可以考虑通过两种方式做到这一点:
当一个对象不再需要对资源的引用时,它必须调用资源管理器的一个方法来表示它不再使用它;或者
当对象不再需要对资源的引用时,它只需将其设置为 null。然后,当要求资源管理器卸载未使用的资源时,它会获取每个资源的引用计数(通过反射?)。如果引用计数为 1(资源管理器将引用该资源),则卸载该资源。
有没有办法在 C# 中实现第二个解决方案?谢谢。
夫妇的事情。首先,对象不被引用计数;引用计数方案存在循环引用问题,即两个对象相互引用但无法访问,从而导致泄漏。.NET 使用不使用引用计数的标记和清除方法。
其次,虽然使用弱引用的建议并不可怕,但也不是灌篮。出于性能原因,您正在构建缓存。(我假设您对应用程序性能特征的仔细、经验和现实的研究已经令人信服地证明了缓存策略对于实现可接受的性能是必要的;如果不是这样,那么您就过早地做出这些决定。)缓存必须有关于何时释放其资源的策略,否则它是内存泄漏。
您怎么知道 GC 保单和您的保单是等效保单?GC 的设计并未考虑到您的特定性能需求。也就是说,它旨在释放真正垃圾的资源,而不是实现您心中的任何特定性能目标。通过将决定委托给 GC,您放弃了根据性能需求调整缓存策略的能力。
在我看来,您可以WeakReference
从资源管理器中使用。GC 将完成其余的工作。你需要做一些铸造,但这很简单,而且会奏效。
class Manager {
Dictionary<string, WeakReference> refs =
new Dictionary<string, WeakReference>();
public object this[string key] {
get {
WeakReference wr;
if (refs.TryGetValue(key, out wr)) {
if(wr.IsAlive) return wr.Target;
refs.Remove(key);
}
return null;
}
set {
refs[key] = new WeakReference(value);
}
}
}
static void Main() {
Manager mgr = new Manager();
var obj = new byte[1024];
mgr["abc"] = obj;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj")
obj = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
Console.WriteLine(mgr["abc"] != null); // false (no remaining refs)
}
我们已经在 .NET 中有一个资源管理器,称为垃圾收集器。因此,一种非常有效的方法是将引用设置为 null 并且什么都不做。
一个更直接的答案:不,没有办法获得对对象的引用。
您可能想研究WeakReference 类或使用缓存系统。
确保资源管理器WeakReference
对您的资源使用 s。这样,当没有其他人引用资源时,他们将有资格进行垃圾收集。
正如其他用户已经告知的那样,您尝试实现的目标已经由 GC 完成,并且可以使用WeakReference进行微调。
这意味着在 .NET、java 等托管环境中,这不是问题。
由于低级框架架构将您与内存管理隔离开来,如果您仍然需要那种功能,我强烈建议您审查自己的代码架构,因为这意味着您在做一些不好的做法内存管理