2009-06-18 16 views
9

ich diese Frage dachte aufrufen, bevor gefragt worden wäre, aber ich konnte es nicht finden Sie hier ...Kraft Java meine C++ destructor (JNI)

Ich habe SWIG verwendet, um eine JNI-Wrapper um eine zu erstellen C++ - Klasse. Alles funktioniert großartig, außer dass Java nie die finalize() der Klasse zu nennen scheint, also wird der Destruktor meiner Klasse nie aufgerufen. Der Destruktor der Klasse führt einige abschließende Datei-I/O aus, also ist dies leider nicht nur ein kleiner Speicherleck.

Bei der Suche über Google scheint es keine Möglichkeit zu geben, Java zum GC zu zwingen und ein Objekt zu zerstören. Wahr?

Ich weiß, ich könnte meine SWIG-Datei manipulieren und erstellen Sie eine Java-Funktion, die den C++ - Destruktor aufrufen würde, aber diese Klasse wird von Endbenutzern in verschiedenen Plattformen/Sprachen verwendet, so dass die Zugabe von einem Java-only erstellen Inkonsequenz, die unsere Tech-Autoren nicht mögen werden.

Antwort

7

Sie können GC nicht mit System.gc() erzwingen. Es ist auch nicht garantiert, dass es jemals einen GC-Lauf geben wird, wenn Ihre App zum Beispiel nur für eine kurze Zeit läuft und dann Ihr Finalizer überhaupt nicht läuft (die JVM führt sie beim Beenden nicht aus). Du solltest eine close() oder destroy() oder was auch immer Funktion für deine Klasse erstellen und wenn du eine Instanz dieser Klasse benutzt hast, rufe sie, vorzugsweise von einem finally Block, wie.


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

Java-Finalizer sind meiner Meinung nach meist nutzlos und sicherlich kein Ersatz für C++ - Destruktoren. Leider hat Java keinen Ersatz für C++ RAII.

Versuchen Sie nicht, die Java-Finalisierung zu erzwingen. Wenn du mit dem was durchgehst, ist alles eine Funktion, die darüber verfügt. Mehr können Sie nicht tun.

0

Fragen wie diese sind der Grund, C#, um die IDisposable Muster für deterministische Finalisierung gewählt haben.

Ich schlage vor, Sie folgen dem gleichen Muster und passen es für Ihre Java-Benutzer.

Erstellen Sie in Ihrer C++ - Klasse eine separate öffentliche Methode, die über Ihre Ressourcen verfügt. Nennen Sie es, schließen Sie oder entsorgen Sie oder etwas.

Lassen Sie Ihren C++ - Destruktor die öffentliche Methode aufrufen und weisen Sie/GC-Benutzer der C++ - Klasse an, dass sie die Methode aufrufen müssen, um Speicherlecks zu vermeiden.

5

Wenn Sie auf Code in der finalize-Methode angewiesen sind, um zu einem bestimmten Zeitpunkt ausgeführt zu werden, müssen Sie Ihren Ansatz überdenken. Das Problem hier ist, dass Sie nicht wissen, wann finalize von der JVM aufgerufen wird, da Sie nicht wissen, wann das Objekt Garbage Collected sein wird.

Eine Sache, die Sie beachten sollten, da Ihre Klasse in anderen Projekten wiederverwendet wird, ist, dass ein Endbenutzer eine Instanz einer Klasse möglicherweise so verwenden kann, dass sie nicht erfasst wird Diese Speicherbereinigung ist unwahrscheinlich, z. B. das Erstellen einer statischen Referenz auf eine Instanz der Klasse. Ich denke, das Erstellen einer close oder destroy Methode ist Ihre sicherste Wette, um sicherzustellen, dass die Ressourcen, die die Instanz der C++ - Klasse, die Ihrem Java-Objekt zugeordnet ist, verwendet werden, ordnungsgemäß freigegeben werden.

Seit wiederverwenden ein Anliegen ist, können Sie den C++ destructor überprüfen, um zu sehen, ob die Ressourcen freigegeben worden war und den gleichen Code zu nennen, wenn sie nicht gewesen wäre, etwa so:

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

Auf diese Weise wird sich Ihr bestehender C++ - Code hoffentlich nicht viel ändern müssen und Sie können sicherstellen, dass Ihre Ressourcen im Kontext von nativem Code, der über JNI läuft, deterministisch freigegeben werden.

3

Nach ein paar mehr durch den SWIG-Code gesehen, sehe ich, dass die SWIG Leute tatsächlich schon damit umgegangen sind - sie fügen eine delete() Funktion für Sie hinzu. Es sieht ziemlich gut nach der Möglichkeit aus, dass sowohl der Programmierer als auch der GC das Objekt löschen können.