必须处理哪些变量? (.NET /爪哇)

时间:2010-08-15 14:03:10

标签: c# java .net garbage-collection dispose

三个问题:

  1. 在.NET / Java中应手动配置哪些变量?我知道SqlConnection应始终手动处理或在using {}块中使用。这样对吗?应该处理的其他变量是什么?

  2. 我在某地读过必须手动处理非托管代码。是对的吗?究竟什么是非托管代码?如何知道变量是托管还是非托管?

  3. 最后,我如何处理变量?我知道Dispose()方法并没有真正处理变量。那么Dispose()做什么呢?我应该将它们设置为null()吗?垃圾收集器的工作原理是什么?

8 个答案:

答案 0 :(得分:5)

此答案仅涉及问题的.NET部分

  

在.NET / Java中应手动配置哪些变量?我知道   应该始终是SqlConnection   要么手动处理,要么用于   使用{}块。这样对吗?是什么   另一种变量   应该处理?

在.NET中,所有实现IDisposable的对象都应该显式处理(或在using块中使用)。

  

我在某地读过必须手动处理非托管代码。是   那对吗?究竟什么是不受管理的   代码以及如何知道变量   是管理还是不管理?

您可能意味着非托管资源,因为代码无法处理...所有使用非托管资源的类(不在托管堆上分配的内存,win32处理......)应该实现IDisposable,并且应该因为它们不是由垃圾收集者管理的,所以要明确处理。

  

最后,我如何处置变量?我知道Dispose()   方法并没有真正处理掉   变量。那么Dispose()做什么呢?   我应该将它们设置为null()吗?什么是   垃圾的逻辑   收藏家的作品?

我不确定我理解你的问题......你没有处理变量,它是由垃圾收集器管理的。所有托管内存在不再使用时会自动释放(即代码无法访问它,因为没有任何引用)。 IDisposable.Dispose方法仅适用于非GC管理的资源。


编辑:作为附注,我想补充说IDisposable 主要是用于清理非托管资源,但也经常用于执行其他清理操作和保证状态或数据完整性。例如,IDbTransaction实现IDisposable以便在事务提交之前发生异常时回滚事务:

using (var trx = connection.BeginTransaction())
{
    // Do some work in the transaction
    ...

    // Commit
    trx.Commit();

} // the transaction is implicitly rolled back when Dispose is called

答案 1 :(得分:4)

在Java中,你“关闭”而不是“处置”。

  • JDBC连接,除非您从池中获取它们。
  • JDBC ResultSet,具体取决于JDBC连接器。
  • InputStreams,OutputStreams,Readers和Writers(除了字节数组和字符串支持的那些)。

某些第三方Java库或框架具有需要手动处理/关闭/销毁的类。

答案 2 :(得分:2)

.NET

  1. 实现IDisposable接口的所有对象都要求在不再需要时调用Dispose方法。 using块只是一个try-finally块的C#sugar,它将IDiposable置于finally块中,只要它不为null即可。因此,即使在try块中抛出异常,也会发生处理。

  2. Unmanaged Code

  3. Dispose方法执行编写Dispose方法的开发人员的任何代码!通常,这涉及释放不受运行时管理的“非托管”资源,例如数据库连接,窗口句柄和文件句柄。请注意,GC管理堆,因此在它引用的对象无法访问之前将引用设置为null并没有多大帮助。

  4. 这是good read

答案 3 :(得分:1)

这主要由托马斯负责,但要扩展第三点:

  

最后,我如何处置变量?我知道Dispose()   方法并没有真正处理掉   变量。那么Dispose()做什么呢?   我应该将它们设置为null()吗?什么是   垃圾的逻辑   收藏家的作品?

他们的关键是Dispose()告诉对象释放它当前持有的任何非托管资源,它不会释放对象本身。

垃圾收集器知道如何释放对象,但对于IDisposable对象,只有对象本身知道如何处置它的私有资源,所以你必须确保在垃圾收集器释放对象之前调用Dispose()

答案 4 :(得分:1)

对于Java:

SWT是一个我们必须处理资源(如图像)的框架,因为框架使用必须释放的本机库和系统句柄。记录SWT课程,并在需要处理时告知。

答案 5 :(得分:1)

跟进其他.NET解决方案......

如果你的对象拥有非托管资源,那么在Dispose()调用上简单地清理它们是不够的,因为你不能保证会调用Dispose。完整的解决方案是:

  1. 为班级添加终结器。
  2. 添加一个名为Disposed的公共bool属性,表示该对象已被释放。
  3. 添加受保护的Dispose(bool)方法。公共Dispose()方法没有参数。
  4. 调用Dispose()时,如果Disposed属性为false,则调用Dispose(true),并调用GC.SuppressFinalize()以禁用终结器。这对于保持.NET垃圾收集器的快乐至关重要。具有未压缩的终结器的类将转到该行的末尾以进行垃圾收集器清理,因此它们几乎成为内存泄漏。
  5. 然后,公共Dispose()方法应将Disposed属性设置为true。
  6. 终结器调用Dispose(false)。
  7. Dispose(bool)将始终清理自己的托管资源,但只有在调用Dispose(true)时才会清理非托管资源。请注意,所有资源清理都在受保护的Dispose(bool)方法中,而不在公共Dispose()方法中。
  8. 如果类没有密封,那么受保护的Dispose(bool)方法应该是一个虚方法。需要进行清理的子类可以覆盖Dispose(bool)并遵循与上面相同的逻辑。另外,他们应该使用给定的参数调用base.Dispose(bool)。

答案 6 :(得分:1)

如果.net,如果你可以在“using”语句中使用一个对象,那意味着该对象实现了iDisposable,你应该在实际调用它时使用它的处理方法。请注意,处理方法可能并不总是称为“Dispose”,但您始终可以通过将对象强制转换为iDisposable然后在其上调用Dispose来调用它。

请注意,某些类型的“iDisposable”对象不处理任何非托管资源,但会订阅事件。如果没有正确处理这样的对象,它可能不会被垃圾收集,除非或直到它为其保存订阅事件的所有对象本身都是垃圾收集的。在某些情况下,这可能永远不会发生,直到应用程序退出。

例如,iEnumerable集合返回的枚举器可能会订阅该对象的“集合已更改”事件,并在调用其dispose方法时取消订阅。如果从未调用dispose方法,则只要集合执行,枚举器就会保持不变。如果集合本身保留了很长时间并且经常被枚举,这可能会造成巨大的内存泄漏。

答案 7 :(得分:1)

我同意上述内容,我只会添加有关将变量设置为null的后续问题。

您不需要对方法中使用的变量执行此操作(它们将超出范围,因此只有当它们在其中具有必须通过IDisposable.Disopse进行清理的状态时才会发出状态担心这个)。

它对于实例或静态成员很少有用,因为内存并不像人们通常认为的那样宝贵( 是一种宝贵的资源,但大多数人试图用几行来处理它)代码就像关闭你的水龙头一样,当你有一个爆裂的主力。

如果你有一个类的静态或实例成员并且(A)它是一个大对象(B),那么“拥有”对象可能会在内存中保留很长时间而且(C)你知道你不需要那个价值增益,把那个成员设置为空。

在实践中,这不是一个非常常见的组合。如果有疑问,请单独留下。

现在,请阅读其他答案,因为他们对Dispose()方法的评价更为重要。