如何确保资源被释放,嵌套对象层次结构?
Posted
技术标签:
【中文标题】如何确保资源被释放,嵌套对象层次结构?【英文标题】:How to make sure resource is released, with nested object hierarchy? 【发布时间】:2015-12-12 15:02:53 【问题描述】:我有这样的代码(简化):
class A
B b = new B();
void close()
b.close();
class B
Closeable mustBeClosed = new Closeable()
System.out.println("create");
@Override
public void close()
System.out.println("close");
;
int n = 0 / 0;
void close()
mustBeClosed.close();
//code
try (A a = new A())
//do something
如何保证mustBeClosed被释放?
当对象层次结构复杂时,可能会发生这种情况。覆盖 B 的 finalize 可能不是一个完美的解决方案。
有针对此问题的最佳实践或原则吗?
修改后的版本如下:
class B
Closeable mustBeClosed;
B()
try
mustBeClosed = ...
//other initialization which might raise exceptions
catch (throwable t)
close();
throw t;
void close()
if (mustBeClosed != null)
try
mustBeClosed.close();
catch (Throwable t)
//all other resources that should be closed
然而,这需要太多的代码并且远非优雅。更重要的是,所有权层次结构中的所有类似乎都应该遵循相同的样式,这会导致大量代码。
有什么建议吗?
【问题讨论】:
【参考方案1】:您的问题是,如果构造函数抛出异常,try-with-resources 将不会(实际上不能)调用close()
。
任何分配资源的对象构造,并且在构造过程中可能会失败在分配资源之后,必须在异常级联之前释放该资源调用堆栈。
两种解决方法:
1) 确保确保资源分配是最后执行的操作。在您的情况下,这意味着将字段 n
移动到字段 mustBeClosed
之前。
2) 在构造函数中而不是在字段初始值设定项中处理资源构造,因此您可以捕获任何后续异常并在重新抛出异常之前再次释放资源,如您的替代解决方案所示。
但是,您不必在 close()
方法中进行 null 检查,因为如果对象构造成功,mustBeClosed
将始终为非 null,而如果对象构造失败,则无法调用 close()
。
【讨论】:
【参考方案2】:使用包装器方法关闭所有Closeable
实例优雅地。
closeGraceFully(Closeable c) // call this guy for all instances of closeable
try
c.close();
catch(IOException ex)
// nothing can be done here, frankly.
然后调用这个包装方法。不要直接打电话给close()
。不要使用finalizers
他们是邪恶的,会减慢你的应用程序。
【讨论】:
以上是关于如何确保资源被释放,嵌套对象层次结构?的主要内容,如果未能解决你的问题,请参考以下文章
Linux内核(linux-5.2.9)--内核对象(对象的引用计数)
C 语言结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )