JNA / ByteBuffer не освобождается и приводит к нехватке памяти кучи C

Позвольте мне начать с того, что мое понимание того, как JNA и Java напрямую распределяют внутреннюю память, в лучшем случае интуитивно, поэтому я пытаюсь описать свое понимание происходящего. Любые исправления в дополнение к ответам было бы здорово ...

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

Я уверен, что мое приложение C не является источником проблемы распределения, так как я передаюjava.nio.ByteBuffer в мой C-код, модифицируя буфер, а затем получая доступ к результату в моей Java-функции. У меня есть одинmalloc и один соответствующийfree во время каждого вызова функции, но после многократного запуска кода в Java malloc в конечном итоге завершится ошибкой.

Вот несколько упрощенный набор кода, который демонстрирует проблему:реально я пытаюсь выделить около 16-32MB на кучу C во время вызова функции.

Мой код Java делает что-то вроде:

public class MyClass{
    public void myfunction(){
        ByteBuffer foo = ByteBuffer.allocateDirect(1000000);
        MyDirectAccessLib.someOp(foo, 1000000);
        System.out.println(foo.get(0));
    }
}

public MyDirectAccessLib{
    static {
        Native.register("libsomelibrary");
    }
    public static native void someOp(ByteBuffer buf, int size);
}

Тогда мой код C может быть что-то вроде:

#include <stdio.h>
#include <stdlib.h>
void someOp(unsigned char* buf, int size){
    unsigned char *foo;
    foo = malloc(1000000);
    if(!foo){
        fprintf(stderr, "Failed to malloc 1000000 bytes of memory\n");
        return;
    }
    free(foo);

    buf[0] = 100;
}

Проблема в том, что после повторного вызова этой функции куча Java несколько стабильна (медленно растет), но функция C в конечном итоге не может выделить больше памяти. На высоком уровне я считаю, что это происходит потому, что Java выделяет память для кучи C, но не очищает ByteBuffer, который указывает на эту память, потому что объект Java ByteBuffer относительно мал.

До сих пор я обнаружил, что запуск GC вручную в моей функции обеспечит необходимую очистку, но это кажется плохой идеей и плохим решением.

Как мне лучше справиться с этой проблемой, чтобы пространство ByteBuffer было соответствующим образом освобождено, а пространство моей кучи C контролировалось?

Правильно ли я понимаю проблему (есть ли что-то, что я запускаю неправильно)?

редактировать: размер буфера отрегулирован так, чтобы он больше отражал мое реальное приложение, я выделяю для изображений примерно 3000x2000 ...

Ответы на вопрос(5)

Ваш ответ на вопрос