После еще одного поиска, я нашел хорошую статью от IBM Research Center.
Вкратце, они рекомендуют использовать кучу Java вместо собственной кучи для собственных объектов. Таким образом, давление памяти на сборщик мусора JVM более реалистично для нативных объектов, на которые ссылаются из кода Java через дескрипторы.
Для этого необходимо переопределить стандартные функции выделения и освобождения кучи C ++: оператор new и оператор delete. В новом операторе, если JVM доступна (JNI_OnLoad уже был вызван), тогда тот вызывает NewByteArray и GetByteArrayElements, который возвращает необходимую выделенную память. Чтобы защитить созданный ByteArray от сбора мусора, необходимо также создать для него NewGlobalRef и сохранить его, например. в том же выделенном блоке памяти. В этом случае нам нужно выделить столько памяти, сколько требуется, плюс память для ссылок. В операторе delete необходимо удалить DeleteGlobalRef и ReleaseByteArrayElements. Если JVM недоступна, вместо нее используются собственные функции malloc и free.