2009-06-18 14 views
9

pensé que esta pregunta habría sido preguntado antes, pero no pude encontrar aquí ...Fuerza Java para llamar a mi C++ destructor (JNI)

he utilizado SWIG para crear un envoltorio alrededor de una JNI Clase de C++ Todo funciona bien, excepto que Java nunca parece llamar al finalize() de la clase, por lo que, a su vez, nunca se llama al destructor de mi clase. El destructor de la clase hace algo de E/S de archivo final, así que desafortunadamente, esto no es solo una fuga de memoria menor.

Buscando a través de Google, no parece haber una manera de forzar a Java a GC y destruir un objeto. ¿Cierto?

Sé que podría manipular mi archivo SWIG y crear una función java que llamaría al destructor C++, pero esta clase es utilizada por los usuarios finales en diferentes plataformas/idiomas, por lo que la adición de un solo Java creará un incoherencia que a nuestros escritores tecnológicos no les va a gustar.

Respuesta

7

No puede forzar GC con System.gc(). Además, no está garantizado que alguna vez se ejecute un GC, por ejemplo, si su aplicación se ejecuta solo por un tiempo breve y luego su finalizador no se ejecutará en absoluto (la JVM no lo ejecutará al salir). Debes crear un close() o destroy() o cualquier función para tu clase y cuando termines de usar una instancia de esta clase llámala, preferiblemente de un bloque finally, como.


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

Los finalizadores de Java son en su mayoría inútiles, en mi opinión, y ciertamente no son un reemplazo para los destructores de C++. Desafortunadamente, Java no tiene reemplazo para C++ RAII.

No se moleste en intentar forzar la finalización de Java. Cuando hayas terminado con lo que sea, toda una función que se deshará de él. Eso es todo lo que puedes hacer.

0

Cuestiones como ésta son la razón C# eligió el patrón IDisposable para su finalización determinista.

Le sugiero que siga el mismo patrón y lo adapte para sus usuarios de Java.

En su clase de C++, cree un método público separado que disponga de sus recursos. Llámalo cerca, o deséchalo, o algo así.

Haga que su destructor de C++ llame al método público y diga a los usuarios de GC/gestión de la clase C++ que deben llamar al método para evitar pérdidas de memoria.

5

Si confía en el código en el método finalize para ejecutar en un momento determinado, debe reconsiderar su enfoque. El problema aquí es que no sabe cuándo la JVM llamará al finalize, ya que no sabe cuándo se recogerá el objeto.

Una cosa que debes considerar, ya que tu clase se reutilizará en otros proyectos, es que es posible que un usuario final pueda usar una instancia de una clase de tal manera que no se recopile o esa recolección de basura será poco probable, como crear una referencia estática a una instancia de la clase. Creo que la creación de un método close o destroy es la apuesta más segura para garantizar que los recursos que utiliza la instancia de la clase C++ asociada a su objeto Java se liberen de forma adecuada.

Dado que la reutilización es una preocupación, usted podría tener el cheque destructor C++ para ver si se habían dado a conocer los recursos y para llamar al mismo código, si no hubieran sido, de este modo:

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(); 
    } 
} 

De esta forma, su código C++ existente no tendrá que cambiar mucho, y puede asegurarse de que sus recursos se liberen de manera determinista en el contexto del código nativo que se ejecuta a través de JNI.

3

Después de mirar un poco más el código producido por SWIG, veo que las personas SWIG ya se han ocupado de esto - agregan una función delete() para usted. Parece bastante bien cuidado de la posibilidad de que tanto el programador como el GC eliminen el objeto también.

Cuestiones relacionadas