Можно ли заставить GC управлять временем жизни нативного объекта? - PullRequest
5 голосов
/ 16 июля 2011

Имея опыт работы с C ++ и C # и небольшие знания Java, я сейчас начинаю проект Java + JNI (C ++) (Android, если это имеет значение).

У меня есть нативный метод, который создает некоторый класс C ++ и возвращает указатель на него как длинное значение Java (скажем, дескриптор). А затем другие нативные методы, вызываемые из кода Java здесь и там, используют дескриптор в качестве параметра для выполнения некоторых нативных операций с этим классом. Сторона C ++ не владеет объектом, а сторона Java, которая имеет. Но в современной архитектуре сложно определить, кому именно принадлежит объект и когда его удалять. Так что, вероятно, было бы неплохо сделать сборщик мусора Java VM, чтобы как-то управлять временем жизни объекта. Класс C ++ не потребляет никаких ресурсов, кроме некоторого фрагмента памяти, небольшого размера. Так что все нормально, если несколько таких объектов не будут разрушены.

В C # я бы, вероятно, обернул нативный дескриптор IntPtr в некоторый управляемый класс-оболочку. И переопределите свой финализатор для вызова деструктора нативного объекта, когда управляемая оболочка собирается сборщиком мусора. SafeHandle, AddMemoryPressure и т. Д. Также могут помочь здесь.

Это другая история с финализацией Java. Второе, что вы знаете после «Hello world» в Java, это то, что использование finalize - это плохо. Есть ли другие способы сделать это в Java? Может быть, с помощью PhantomReference?

Ответы [ 4 ]

5 голосов
/ 16 июля 2011

Хорошо, давайте рассмотрим причину, почему финализация и Co проблематичны: как вы знаете, нет никакой гарантии, что финализация будет вызвана до выключения виртуальной машины, что означает, что специальный код очистки не обязательно будет запущен (это плохое решение Я не вижу проблем с прохождением очереди завершения при очистке, но это так). Также это точно такая же ситуация в C #

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

Также обратите внимание, что реализация финализатора приводит к некоторым дополнительным издержкам для GC и означает, что для очистки одного из этих объектов требуется два цикла (и что бы вы ни делали, никогда не сохраняйте объект в методе finalize)

2 голосов
/ 16 июля 2011

Если вы понимаете, почему вам следует избегать использования метода finalize в Java, вы также поймете, как правильно его использовать. Использование finalize для закрытия системных ресурсов (файлов и дескрипторов) плохо, потому что вы на самом деле не знаете, когда эти ресурсы будут закрыты и освобождены. Использование сложной логики финализации плохо, так как ссылка на ваш объект может просочиться и снова застрять в памяти.

Для вашего сценария идеально подходит финализация.

1 голос
/ 16 июля 2011

использование обертки с финализатором - достойное решение здесь

но если вы действительно не хотите этого делать, вы можете использовать PhantomReference с ReferenceQueue, чтобы очистить его (но вам потребуется отдельный поток для опроса очереди)

0 голосов
/ 09 ноября 2016

Так, как мы можем достигнуть этого, используя фантомную ссылку.

  1. Создайте объект-оболочку для вашего собственного объекта intPtr. Создать фантомная ссылка (с очередью ссылок) на объект-оболочку.
  2. Создание и поддержка карты фантомных ссылок на intPtr.
  3. Создать поток, который будет отслеживать очередь ссылок для завершения экземпляры объекта-оболочки.
  4. Этот поток будет получать ссылку на фантом из справочной очереди, поиск intPtr с использованием ссылки на фантом и деструктор вызова для нативного объекта int, на который ссылается intPtr.
  5. Пока все это происходит, вы можете спокойно пользоваться объект-обертка в вашем коде Java.
...