2009-06-18 16 views
9

myślałem, że to pytanie byłaby poproszony wcześniej, ale nie mogłem go znaleźć tutaj ...Siła Java, aby zadzwonić do mojego C++ destruktora (JNI)

Użyłem SWIG stworzyć opakowanie JNI wokó? Klasa C++. Wszystko działa świetnie, z wyjątkiem tego, że Java nigdy nie wywołuje finalizacji klasy(), więc z kolei destruktor mojej klasy nigdy nie zostanie wywołany. Destrukcja klasy wykonuje końcowe operacje wejścia/wyjścia pliku, więc niestety nie jest to tylko niewielki wyciek pamięci.

Wyszukiwanie przez Google nie wydaje się być sposobem na wymuszenie Javy na GC i zniszczeniem obiektu. Prawdziwe?

Wiem, że mógłbym manipulować moim plikiem SWIG i utworzyć funkcję java, która wywoływałaby destruktor C++, ale ta klasa jest używana przez użytkowników końcowych na kilku różnych platformach/językach, więc dodanie opcji Java-only stworzy niekonsekwencja, której nasi technicy nie polubią.

Odpowiedz

7

Nie można wymusić GC z System.gc(). Nie można też zagwarantować, że kiedykolwiek uruchomi się GC, jeśli aplikacja będzie działać tylko przez krótki czas, a wtedy finalizator nie uruchomi się wcale (maszyna JVM nie uruchomi go przy wychodzeniu). Powinieneś utworzyć funkcję close() lub destroy() lub inną dla swojej klasy, a kiedy skończysz używać instancji tej klasy, wywołaj ją, najlepiej z bloku finally, na przykład.


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

Korektory Java są w większości przypadków bezużyteczne, moim zdaniem, a na pewno nie zastępują destruktorów C++. Niestety, Java nie zastępuje C++ RAII.

Nie próbuj wymuszać finalizacji Java. Kiedy przejdziesz przez cokolwiek, wszystkie funkcje, które się go pozbędą. To wszystko, co możesz zrobić.

0

Problemy takie jak ten są powodem C# wybrali wzór IDisposable dla deterministycznego finalizacji.

Proponuję zastosować ten sam wzór i dostosować go do swoich użytkowników Java.

W swojej klasie C++ utwórz oddzielną, publiczną metodę, która pozbawia twoje zasoby. Nazwij to blisko, albo wyrzuć, czy coś.

Niech twój destruktor C++ wywoła publiczną metodę i powiedz zarządzanym/GC użytkownikom klasy C++, że muszą wywołać tę metodę, aby uniknąć wycieków pamięci.

5

Jeśli polegasz na kodzie w metodzie finalize, aby uruchomić w określonym czasie, musisz ponownie rozważyć swoje podejście. Problem polega na tym, że nie wiesz, kiedy JVM wywoła finalize, ponieważ nie wiesz, kiedy obiekt zostanie zebrany.

Jedną z rzeczy, które powinieneś rozważyć, ponieważ twoja klasa zostanie ponownie wykorzystana w innych projektach, jest to, że możliwe jest, że użytkownik końcowy może użyć instancji klasy w taki sposób, że nie zostanie ona zebrana lub to usuwanie śmieci będzie mało prawdopodobne, na przykład tworzenie statycznego odwołania do instancji klasy. Myślę, że najbezpieczniejszym sposobem jest stworzenie metody close lub destroy, aby upewnić się, że zasoby, których używa instancja klasy C++ powiązanej z obiektem Java, są odpowiednio publikowane.

Ponieważ ponowne wykorzystanie jest problemem, można mieć C++ czek destructor, aby sprawdzić, czy środki zostały zwolnione i wywołać ten sam kod, gdyby nie było, tak jak poniżej:

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

W ten sposób twój istniejący kod C++ z pewnością nie będzie musiał wiele zmieniać i możesz zapewnić, że twoje zasoby są uwalniane w deterministyczny sposób w kontekście natywnego kodu działającego przez JNI.

3

Po dokładniejszym obejrzeniu kodu wygenerowanego przez SWIG widzę, że ludzie z SWIG faktycznie już to zrobili - dodają dla ciebie funkcję delete(). Wygląda na to, że zadbano również o to, aby zarówno programista, jak i GC usunęli obiekt.

Powiązane problemy