Заставить Java вызывать мой деструктор C ++ (JNI) - PullRequest
9 голосов
/ 18 июня 2009

Я думал, что этот вопрос задали бы раньше, но я не смог найти его здесь ...

Я использовал SWIG для создания оболочки JNI вокруг класса C ++. Все прекрасно работает, за исключением того, что Java никогда не вызывает finalize () класса, поэтому, в свою очередь, деструктор моего класса никогда не вызывается. Деструктор класса выполняет окончательный файловый ввод-вывод, поэтому, к сожалению, это не просто небольшая утечка памяти.

Поиск в Google, похоже, не позволяет принудительно заставить Java GC уничтожить объект. Правда?

Я знаю, что мог бы манипулировать своим SWIG-файлом и создать Java-функцию, которая вызывала бы деструктор C ++, но этот класс используется конечными пользователями на нескольких различных платформах / языках, поэтому добавление только Java создаст несоответствие что нашим техническим писателям не понравится.

Ответы [ 5 ]

7 голосов
/ 18 июня 2009

Вы не можете форсировать GC с помощью System.gc (). Также не гарантируется, что когда-либо будет запущен сборщик мусора, например, если ваше приложение запускается только в течение короткого времени, а затем ваш финализатор вообще не будет работать (JVM не запускает его при выходе). Вы должны создать функцию close () или destroy () или любую другую функцию для вашего класса, и когда вы закончили использовать экземпляр этого класса, вызовите его, предпочтительно из блока finally, например.


MyClass x = null;
try{
    x = new MyClass();
    x.work();
} finally {
    if (x!=null)
        x.close();
}
5 голосов
/ 19 июня 2009

Если вы полагаетесь на код в методе finalize для запуска в определенное время, вам необходимо пересмотреть свой подход. Проблема в том, что вы не знаете, когда JVM будет вызывать finalize, поскольку вы не знаете, когда объект будет собирать мусор.

Одна вещь, которую вы должны учитывать, поскольку ваш класс будет повторно использоваться в других проектах, это то, что конечный пользователь может использовать экземпляр класса таким образом, что он не будет собран, или что сборка мусора будет маловероятной, например, создание статической ссылки на экземпляр класса. Я думаю, что создание метода close или destroy - это ваша самая безопасная ставка, чтобы гарантировать, что ресурсы экземпляра класса C ++, связанного с вашим объектом Java, будут освобождены соответствующим образом.

Поскольку повторное использование является проблемой, вы могли бы проверить деструктор 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();
  }
}

Таким образом, ваш существующий код C ++, надеюсь, не будет сильно меняться, и вы можете гарантировать, что ваши ресурсы будут освобождены детерминистическим способом в контексте нативного кода, выполняемого через JNI.

5 голосов
/ 18 июня 2009

Финализаторы Java по большей части бесполезны, на мой взгляд, и, конечно, не являются заменой деструкторам C ++. К сожалению, Java не может заменить C ++ RAII.

Не пытайтесь форсировать завершение Java. Когда вы закончите с чем угодно, все функции, которые будут избавляться от него. Это все, что вы можете сделать.

3 голосов
/ 19 июня 2009

После еще одного просмотра кода, созданного SWIG, я вижу, что специалисты SWIG на самом деле уже имели дело с этим - они добавляют функцию delete () для вас. Он выглядит вполне прилично позаботившимся о возможности удаления объекта и программистом, и GC.

0 голосов
/ 19 июня 2009

Подобные проблемы являются причиной, по которой C # выбрал шаблон IDisposable для детерминированной финализации.

Я предлагаю вам следовать тому же шаблону и адаптировать его для ваших пользователей Java.

В вашем классе c ++ создайте отдельный публичный метод, который избавляется от ваших ресурсов. Назовите это близко, или избавьтесь, или что-то.

Пусть ваш деструктор C ++ вызовет открытый метод и скажет управляемым пользователям / пользователям GC класса C ++, что они должны вызвать метод, чтобы избежать утечек памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...