Позвольте мне начать с того, что мое понимание того, как JNA и Java направляют собственное распределение памяти в лучшем случае, является в лучшем случае внутренним, поэтому я пытаюсь описать свое понимание того, что происходит. Любые исправления в дополнение к ответам были бы великолепны ...
Я запускаю приложение, которое смешивает собственный код Java и C, используя JNA, и сталкиваюсь с воспроизводимой проблемой, когда сборщик мусора Java не может освободить ссылки на прямые выделения собственной памяти, что приводит к нехватке памяти кучи C.
Я уверен, что мое приложение C не является источником проблемы выделения, поскольку я передаю java.nio.ByteBuffer
в свой код C, изменяю буфер и затем получаю доступ к результату в моей функции Java. У меня есть один malloc
и один соответствующий free
во время каждого вызова функции, но после многократного запуска кода на Java malloc в конечном итоге завершится ошибкой.
Вот несколько упрощенный набор кода, который демонстрирует проблему - реально я пытаюсь выделить около 16-32 МБ в куче 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 ...