Força Java para chamar meu destrutor C ++ (JNI)
-
06-07-2019 - |
Pergunta
Eu pensei que esta questão teria sido solicitado antes, mas eu não poderia encontrá-lo aqui ...
Eu usei SWIG para criar um wrapper JNI em torno de uma classe C ++. Todos os trabalhos grandes, exceto que Java nunca parece chamar finalize da classe (), então, por sua vez, destruidor da minha classe nunca é chamado. destructor da classe faz algum arquivo final I / O, então, infelizmente, isso não é apenas uma fuga de memória menor.
Como pesquisar através do Google, não parece ser uma maneira de forçar Java para GC e destruir um objeto. Verdade?
Eu sei que eu poderia manipular meu arquivo SWIG e criar uma função java que iria chamar o destruidor C ++, mas esta classe é usada pelos usuários finais em vários diferentes plataformas / linguagens, então a adição de um Java-só irá criar uma inconsistência que nossos escritores de tecnologia não vão gostar.
Solução
Você não pode forçar GC com System.gc (). Também não é garantido que nunca haverá uma corrida GC por exemplo, se o seu aplicativo é executado apenas por um curto período de tempo e, em seguida, o seu finalizador não será executado em todos (a JVM não executá-lo quando sair). Você deve criar um close () ou destruir () ou qualquer função para a sua classe e quando você terminar de usar uma instância dessa chamada classe-lo, de preferência a partir de um bloco finally, como.
MyClass x = null;
try{
x = new MyClass();
x.work();
} finally {
if (x!=null)
x.close();
}
Outras dicas
Java são praticamente inúteis, na minha opinião, e certamente não um substituto para destruidores C ++. Infelizmente, Java não tem substituto para C ++ RAII.
Não se preocupe em tentar forçar a finalização Java. Quando você está completamente com o que quer, tudo uma função que irá descartá-lo. Isso é tudo o que você pode fazer.
Se você está confiando em código no método finalize
para executar em um determinado momento, você precisa reconsiderar sua abordagem. O problema aqui é que você não sabe quando finalize
será chamado pela JVM, desde que você não sabe quando o objeto será coletado.
Uma coisa que você deve considerar, desde a sua classe será em outros projetos reutilizado, é que é possível que um usuário final pode usar uma instância de uma classe de tal forma a que não serão recolhidos ou que recolha de lixo será improvável, tais como a criação de uma referência estática para uma instância da classe. Eu acho que a criação de um close
ou método destroy
é a sua aposta mais segura de garantir que os recursos da instância da classe do C ++ associado com o objeto Java está usando são liberados de forma adequada.
Uma vez que a reutilização é uma preocupação, você poderia ter o cheque destrutor C ++ para ver se os recursos foram liberados e chamar o mesmo código, se não tivessem sido, assim:
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();
}
}
Desta forma, seu código existente C ++ espero que não terá que mudar muito, e você pode garantir que seus recursos são liberados de forma determinística no contexto de código nativo rodando via JNI.
Depois de um pouco mais olhando através do código de SWIG-produzido, vejo que as pessoas SWIG realmente já lidaram com isso - eles adicionar uma função delete () para você. Parece que muito bem cuidado a possibilidade de tanto o programador e o GC excluir o objeto também.
Questões como esta são a razão C # escolheu o IDisposable padrão para a finalização determinística.
Eu sugiro que você siga o mesmo padrão e adaptá-lo para seus usuários Java.
Na sua classe c ++, criar um método separado, público que dispõe de seus recursos. Chamá-lo de perto, nem descarte, ou algo assim.
Tenha o seu destruidor C ++ chamar o método público, e informar aos usuários gerenciados / GC da classe C ++ que eles devem chamar o método para evitar vazamentos de memória.