我有一个创建成本昂贵的对象,它使用一些必须在完成时显式释放的非托管资源,因此实现IDisposable() . 我想要一个缓存,例如这些昂贵的资源,以便最大限度地降低创建成本,但我很难知道如何处理这些处理 .
如果使用这些对象的方法负责处理,那么我最终会在缓存中放置已处理的实例,然后必须重新创建实例,从而破坏缓存的重点 . 如果我没有在使用它们的方法中处理对象,那么它们永远不会被处理掉 . 我认为当它们从缓存中取出时我可以处理它们,但是我可能最终会处理一个仍被方法使用的实例 .
让它们超出范围并由垃圾收集器收集并在那时释放资源是否有效?这感觉不对,并反对他们是一次性的想法......
6 回答
一次性物品总是需要有一个明确的所有者负责处理它们 . 但是,这并不总是创建它们的对象 . 此外,所有权可以转移 .
意识到这一点,解决方案变得显而易见 . Don't dispose, recycle! 您不仅需要一种从缓存中获取资源的方法,还需要一种返回资源的方法 . 此时缓存是所有者,并且可以选择保留资源以供将来使用或处置它 .
edit: 我刚刚注意到这个想法在Spring中也存在,它被称为object pool . 他们的
BorrowObject
和ReturnObject
方法与我的示例中的方法匹配 .To(mis-)引用Raymond Chen:没有过期策略的每个缓存都是泄漏
因此,设置一个清除缓存过期策略,并让缓存将它们作为正常情况进行处理 . 这仍然会使应用程序关闭处理 .
如果您的非托管资源由流程拥有,您可以让流程在关闭时释放它们 .
如果进程拥有非托管资源,则需要检测shutdown并明确地释放缓存的元素 .
如果您无法可靠地检测进程关闭,并且托管资源很昂贵,则非托管资源不是,将托管与非托管资源分开,并让缓存仅保留托管资源 .
当非托管资源很昂贵,因此它们需要缓存,而且它们不属于流程所有,并且您无法可靠地检测到流程关闭而且您无法承受泄漏,那么您的问题就无法解决 .
首先,包装本机资源的类型应该是最终的,而不仅仅是一次性的 . 更好的是,使用SafeHandle来包装本机资源 .
除非某人明确负责说他们已完成该项目并且可以处理它,否则我认为你最好让GC处理它 . 请注意,它必须是可以最终确定的,否则GC不会给它第二眼 .
您可以将非托管资源与托管实例分离,并使用缓存管理器来保存一组非托管资源 . 托管对象将尝试从缓存管理器获取非托管资源的实例,该实例将创建一个或从缓存中提供一个空闲实例,并在处置时将其返回到缓存管理器(而不是自己处理) . . 缓存管理器将是唯一负责的对象,用于在看到必要时分配和释放非托管资源 .
您可以使用类工厂和IDisposable解决此问题 . 例如:
对象应由创建它的类处理 . 由于您的调用者尚未在缓存中创建项目,因此他们也没有业务处理它们 .
我想确保您的工厂方法的名称类似于“GetClass " rather than " CreateClass”,以强调调用者不负责创建,因此不负责处理 .