我以前会问这个问题,但我在这里找不到......
我使用SWIG围绕C ++类创建了一个JNI包装器。一切都很好,除了Java似乎永远不会调用类的finalize(),反过来,我的类的析构函数永远不会被调用。类的析构函数执行一些最终文件I / O,所以不幸的是,这不仅仅是一个小的内存泄漏。
通过Google搜索,似乎没有办法强制Java加入GC并销毁对象。真?
我知道我可以操作我的SWIG文件并创建一个可以调用C ++析构函数的java函数,但是这个类被几个不同平台/语言的最终用户使用,所以添加一个Java只会产生不一致我们的技术作家不喜欢。
答案 0 :(得分:7)
您无法使用System.gc()强制GC。 此外,如果您的应用程序仅运行一小段时间,然后您的终结器根本不运行(JVM在退出时不运行它),则无法保证会运行GC。你应该为你的类创建一个close()或destroy()或者任何函数,当你完成使用这个类的实例时,最好从finally块中调用它,比如。
MyClass x = null;
try{
x = new MyClass();
x.work();
} finally {
if (x!=null)
x.close();
}
答案 1 :(得分:5)
不要试图强制Java终结。当你通过任何事情,所有的功能将处理它。这就是你所能做的一切。
答案 2 :(得分:5)
如果您依靠finalize
方法中的代码在特定时间运行,则需要重新考虑您的方法。这里的问题是你不知道JVM何时会调用finalize
,因为你不知道该对象何时会被垃圾收集。
您应该考虑的一件事,因为您的类将在其他项目中重复使用,最终用户可能会以不会被收集的方式使用类的实例或者垃圾收集不太可能,例如创建对类实例的静态引用。我认为创建close
或destroy
方法是最安全的选择,以确保与Java对象关联的C ++类实例所使用的资源得到适当的释放。
由于重用是一个问题,你可以让C ++析构函数检查资源是否已经释放,如果没有,则调用相同的代码,如下所示:
class MyThing {
public:
void close();
~MyThing();
private:
bool released = false;
};
void
MyThing::close() {
// close logic here
this->released = true;
}
MyThing::~MyThing() {
if (!released) {
this->close();
}
}
这样,您现有的C ++代码可能不会有太大变化,您可以确保在通过JNI运行的本机代码的上下文中以确定的方式发布资源。
答案 3 :(得分:3)
在浏览了SWIG产生的代码后,我发现SWIG人员已经处理过这个问题了 - 他们为你添加了一个delete()函数。它看起来很好地照顾了程序员和GC同时删除对象的可能性。
答案 4 :(得分:0)
这样的问题是C#选择IDisposable模式进行确定性终结的原因。
我建议您遵循相同的模式并为您的Java用户进行调整。
在您的c ++类中,创建一个单独的公共方法来处理您的资源。称之为关闭,或处置,或其他什么。
让您的C ++析构函数调用public方法,并告诉C ++类的managed / GC用户必须调用该方法以避免内存泄漏。