简体   繁体   English

强制Java调用我的C ++析构函数(JNI)

[英]Force Java to call my C++ destructor (JNI)

I thought this question would have been asked before, but I couldn't find it here... 我以前会问这个问题,但我在这里找不到......

I've used SWIG to create a JNI wrapper around a C++ class. 我已经使用SWIG在C ++类周围创建了一个JNI包装器。 All works great except that Java never seems to call the class's finalize(), so, in turn, my class's destructor never gets called. 一切都很好,除了Java似乎永远不会调用类的finalize(),反过来,我的类的析构函数永远不会被调用。 The class's destructor does some final file I/O, so unfortunately, this isn't just a minor memory leak. 类的析构函数执行一些最终文件I / O,所以不幸的是,这不仅仅是一个小的内存泄漏。

Searching through Google, there doesn't seem to be a way to force Java to GC and destroy an object. 通过Google搜索,似乎没有办法强制Java到GC并销毁对象。 True? 真正?

I know I could manipulate my SWIG file and create a java function that would call the C++ destructor, but this class is used by end users in several different platforms/languages, so the addition of a Java-only will create an inconsistency that our tech writers aren't going to like. 我知道我可以操作我的SWIG文件并创建一个可以调用C ++析构函数的java函数,但是这个类被最终用户用在几种不同的平台/语言中,所以添加一个Java只会产生我们的技术不一致作家们不会喜欢。

You can't force GC with System.gc(). 您无法使用System.gc()强制GC。 Also it is not guaranteed that there will ever be a GC run for example if your app runs only for a short time and then your finalizer won't run at all (the JVM does not run it when exiting). 此外,如果您的应用程序仅运行一小段时间,然后您的终结器根本不运行(JVM在退出时不运行它),则无法保证会运行GC。 You should create a close() or destroy() or whatever function for your class and when you finished using an instance of this class call it, preferably from a finally block, like. 你应该为你的类创建一个close()或destroy()或者任何函数,当你完成使用这个类的实例时,最好从finally块中调用它。


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

Java finalizers are mostly useless, in my opinion, and certainly not a replacement for C++ destructors. 在我看来,Java终结器几乎没用,当然也不能替代C ++析构函数。 Unfortunately, Java has no replacement for C++ RAII. 不幸的是,Java没有替代C ++ RAII。

Don't bother trying to force Java finalization. 不要试图强制Java完成。 When you're through with the whatever, all a function that will dispose of it. 当你通过任何事情,所有的功能将处理它。 That's all you can do. 这就是你所能做的一切。

If you're relying on code in the finalize method to run at a certain time, you need to reconsider your approach. 如果您依靠finalize方法中的代码在特定时间运行,则需要重新考虑您的方法。 The problem here is that you don't know when finalize will be called by the JVM, since you don't know when the object will be garbage collected. 这里的问题是你不知道JVM何时会调用finalize ,因为你不知道该对象何时会被垃圾收集。

One thing that you should consider, since your class will be re-used in other projects, is that it's possible that an end-user could use an instance of a class in such a way that it will not be collected or that garbage collection will be unlikely, such as creating a static reference to an instance of the class. 您应该考虑的一件事是,因为您的类将在其他项目中重用,所以最终用户可能会以这样的方式使用类的实例,使得它不会被收集或者垃圾收集将会不太可能,例如创建对类实例的静态引用。 I think creating a close or destroy method is your safest bet to ensure that the resources the instance of the C++ class associated with your Java object is using are released appropriately. 我认为创建closedestroy方法是确保与Java对象关联的C ++类实例正在使用的资源得到适当释放的最安全的选择。

Since re-use is a concern, you could have the C++ destructor check to see if the resources had been released and to call the same code if they hadn't been, like so: 由于重用是一个问题,你可以让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();
  }
}

This way, your existing C++ code hopefully won't have to change much, and you can ensure that your resources are released in a deterministic way in the context of native code running via JNI. 这样,您现有的C ++代码有望不会发生太大变化,并且您可以确保在通过JNI运行的本机代码的上下文中以确定的方式发布资源。

After some more looking through the SWIG-produced code, I see that the SWIG people actually have already dealt with this -- they add a delete() function for you. 在看了一下SWIG生成的代码之后,我看到SWIG人员实际上已经处理了这个问题 - 他们为你添加了一个delete()函数。 It looks to pretty well taken care of the possibility of both the programmer and the GC deleting the object as well. 它看起来很好地照顾了程序员和GC同时删除对象的可能性。

Issues like this are the reason C# chose the IDisposable pattern for deterministic finalization. 像这样的问题是C#选择IDisposable模式进行确定性终结的原因。

I suggest you follow the same pattern and adapt it for your Java users. 我建议你遵循相同的模式,并为你的Java用户进行调整。

In your c++ class, create a separate, public method that disposes of your resources. 在您的c ++类中,创建一个单独的公共方法来处理您的资源。 Call it close, or dispose, or something. 称之为关闭,或处置,或其他东西。

Have your C++ destructor call the public method, and tell managed/GC users of the C++ class that they must call the method to avoid memory leaks. 让您的C ++析构函数调用公共方法,并告诉C ++类的托管/ GC用户必须调用该方法以避免内存泄漏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM