我以前会问这个问题,但我在这里找不到......

我使用SWIG围绕C ++类创建了一个JNI包装器。一切都很好,除了Java似乎永远不会调用类的finalize(),因此反过来,我的类的析构函数永远不会被调用。类的析构函数执行一些最终文件I / O,所以不幸的是,这不仅仅是一个小的内存泄漏。

通过Google搜索,似乎没有办法强制Java加入GC并销毁对象。真?

我知道我可以操作我的SWIG文件并创建一个可以调用C ++析构函数的java函数,但是这个类被几个不同平台/语言的最终用户使用,所以添加一个Java只会产生不一致我们的技术作家不喜欢。

有帮助吗?

解决方案

您无法使用System.gc()强制GC。 此外,如果您的应用程序仅运行一小段时间,然后您的终结器根本不运行(JVM在退出时不运行它),则无法保证会运行GC。你应该为你的类创建一个close()或destroy()或者任何函数,当你完成使用这个类的实例时,最好从finally块中调用它,比如。


MyClass x = null;
try{
    x = new MyClass();
    x.work();
} finally {
    if (x!=null)
        x.close();
}

其他提示

在我看来,Java终结器几乎没用,当然也不能替代C ++析构函数。不幸的是,Java没有替代C ++ RAII。

不要试图强制Java终结。当你通过任何事情,所有的功能将处理它。这就是你所能做的一切。

如果您依赖 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运行的本机代码的上下文中以确定的方式发布资源。

在浏览了SWIG产生的代码后,我发现SWIG人员已经处理过这个问题了 - 他们为你添加了一个delete()函数。它看起来很好地照顾了程序员和GC同时删除对象的可能性。

scroll top