【发布时间】:2011-07-15 22:58:09
【问题描述】:
凭借 C++ 和 C# 经验以及一些 Java 知识,我现在开始了一个 Java+JNI (C++) 项目(Android,如果这很重要的话)。
我有一个本地方法,它创建一些 C++ 类并将指向它的指针作为 Java long 值(例如句柄)返回。然后从 Java 代码中调用的其他本地方法,使用句柄作为参数对这个类进行一些本地操作。 C++ 端不拥有对象,Java 端拥有。但是在当前的架构设计中,很难定义谁确切拥有该对象以及何时删除它。因此,让 Java VM 垃圾收集器以某种方式管理对象的生命周期可能会很好。 C++ 类不消耗任何资源,除了一些内存,不是很大。所以没关系,如果几个这样的对象不会被破坏。
在 C# 中,我可能会将本机 IntPtr 句柄包装在一些托管包装类中。并在托管包装器被垃圾收集时覆盖它的终结器以调用本机对象的析构函数。 SafeHandle、AddMemoryPressure 等可能在这里也有帮助。
这与 Java 的 finalize 不同。在 Java 中的“Hello world”之后,您知道的第二件事是使用 finalize 是不好的。有没有其他方法可以在 Java 中实现这一点?也许使用 PhantomReference?
【问题讨论】:
-
在 C# 中使用终结器是“不好的”,原因与在 Java 中不好的原因相同 - 那么有什么区别?
-
看看 BlueRaja 怎么说 ;-) C# 使用
IDisposable而 Java 经常使用Closable接口。这些定义了生命周期的合同——但是是手动构造的。 (C# 支持using,Java7 将支持类似的东西。)C# 和 Java 的“问题”是使用的 GC(在当前实现中)不是引用计数并且是一个惰性标记/sweep hybrid——也就是说,为了一般的论证,GC的实际时间是“不确定的”。终结器或任何 *Reference 的问题在于 它们无法“看到”其他系统资源的压力。 -
@pst:不,真正的问题是你不能保证终结器会在虚拟机关闭之前运行,你可以简单地解决这个问题(至少它是如何在 Java 中实现的) GC算法。而且我看不出对其他系统资源的压力与它有什么关系-如果对象仍在使用中,则无法释放它,并且如果它不是完整的 GC 将始终找到并释放它(现在 VM 没有'不关心任何事情,但记忆是真实的,但如果这是一个问题,那可以再次修复)
-
正如我所说,我只有一点 Java 知识,所以我可能看不出为什么 finalize 在 Java 中“不好”的所有确切原因。至于C#,它不被认为是坏的。至少,例如,Richter 通过 C# 编写的 CLR 有一整章“使用终结化来释放本机资源”。此外,诸如 GC.AddMemoryPressure 或 HandleCollector 类之类的方法表明,.NET 团队实际上打算使用终结器来管理本机资源。
-
@Alex Che:没有读过那本书,但是如果你在终结器中处理资源,当操作系统关闭进程时不会自动释放(EXTREMELY 危险和糟糕的建议。 .NET 团队添加 IDisplosable 接口是有原因的,并不是“以不同的方式收集资源会很有趣”
标签: java memory-management garbage-collection java-native-interface native