Опитвам се да създам обвързване на C библиотека към моя Java код с JNA, но получавам много лошо представяне.
Ето C заглавния файл
struct facet_fin_s {
int facet;
int fin;
};
typedef struct facet_fin_s facet_fin_t;
struct tab_facet_fin_s {
facet_fin_s *data;
int length;
};
typedef struct tab_facet_fin_s tab_facet_fin_t;
struct facet_s{
int number_of_fins;
tab_facet_fin_s tab_facet_fin;
};
typedef struct facet_s facet_t;
extern "C" __declspec(dllexport) void getFins(facet_t* const );
Ето C файла
void getFins(facet_t* const facet)
{
facet->number_of_fins = 258246;
facet->tab_facet_fin.length = facet->number_of_fins;
facet->tab_facet_fin.data = (facet_fin_s*)malloc(sizeof(facet_fin_s) * facet->tab_facet_fin.length);
memset(facet->tab_facet_fin.data, 0, sizeof(facet_fin_s) * facet->tab_facet_fin.length);
int loop = 0;
for (loop=0; loop<facet->tab_facet_fin.length; loop++)
{
facet_fin_s fin;
fin.facet = loop;
fin.fin = loop;
facet->tab_facet_fin.data[loop] = fin;
}
}
и накрая моят тест в Java
facet_s retFacet = new facet_s();
TestJNABindingLibrary.getFins(retFacet);
Structure facetFin[] = retFacet.tab_facet_fin.data.toArray(retFacet.tab_facet_fin.length);
for (int i = 0; i < facetFin.length; i++)
{
System.out.println(((facet_fin_s)facetFin[i]).fin);
System.out.println(((facet_fin_s)facetFin[i]).facet);
}
Резултатите, върнати от моята функция getFins, са правилни, но операцията е наистина бавна. Реших, че извикването на "toArray" на retFacet.tab_facet_fin.data отнема 38 секунди!!
Мисля, че JNA прекарват твърде много време, за да синхронизират структурите на Java с родната структура и да копират данните.
Опитах байтовите масиви и ByteBuffer за директен достъп до паметта без копиране, но тези методи са удобни за примитивни обекти, а не за структури. Също така се опитах да играя с указатели за лесен достъп до данните, но без успех.
Моята цел е да намеря начин да подобря представянето и все още да поддържам Java кода ясен и лесен за манипулиране (ще имам много от тези функции в проекта). Има ли някакъв начин да се постигне това с JNA? (Вече разгледах JNI, SWIG и BridJ..). Някои кодове са добре дошли ;-)
Благодаря
РЕДАКТИРАНЕ
Ето моя опит да деактивирам автоматичното синхронизиране и да прочета полето
facet_s retFacet = new facet_s();
retFacet.setAutoSynch(false);
TestJNABindingLibrary.getFins(retFacet);
facet_fin_s[] fins = (facet_fin_s[])retFacet.tab_facet_fin.readField("data");
за съжаление fins
изглежда null
РЕДАКТИРАНЕ 2
Technomage ми каза, че първо трябва да прочета tab_facet_fin
. Но все още не мога да получа резултатите като масив.
tab_facet_fin_s tab = (tab_facet_fin_s)retFacet.readField("tab_facet_fin");
facet_fin_s[] fins = (facet_fin_s[])tab.readField("data");
повдига изключение за предаване. Има ли някакъв лесен начин за четене на това поле?
РЕДАКТИРАНЕ 3
Благодарение на Technomage изпробвах напълно стратегията readField
. Има два начина за получаване на данните, в зависимост дали data
е Pointer
или Structure.ByReference
.
тук е общата част (всеки Java клас извиква setAutoSynch(false)
в своя конструктор)
facet_s retFacet = new facet_s();
TestJNABindingLibrary.getFins(retFacet);
след това случаят Pointer
int length = (int)retFacet.readField("number_of_fins");
tab_facet_fin_s tab = (tab_facet_fin_s)retFacet.readField("tab_facet_fin");
int[] data = new int[length*2];
tab.data.read(0, data, 0, data.length);
for (int i = 0; i < data.length; i++)
{
System.out.println(data[i]);
}
или случаят Structure.ByReference
.
tab_facet_fin_s tab = (tab_facet_fin_s)retFacet.readField("tab_facet_fin");
facet_fin_s s = (facet_fin_s)tab.readField("data");
facet_fin_s[] data = (facet_fin_s[])s.toArray(length);
for (int i = 0; i < data.length; i++)
{
System.out.println(data[i].fin);
System.out.println(data[i].facet);
}
Сега моето мнение:
Стратегията
readField
може да бъде добър начин за оптимизиране на представянето и избягване на безполезно копиране. Това може да е добър трик, но не е от значение тук, защото структурата ми има само данни, които искам да прочета. Ако другите ми структури в моя проект съдържат данни, които не искам да чета, тогава ще ги използвам окончателно.Случаят с указател: За съжаление, JNAerator автоматично генерира моя
data
катоStructure.ByReference
, а неPointer
. Но нека си представим, че получавам тезиPointer
. Тогава мога също така да имам достъп до int стойностите в данните много бързо. Ако не греша, този начин е абсолютно същият като да се обадите наPointer.getIntArray
. Тук виждам 2 проблема. Първо, напълно губя предимството да имамfacet_fin_s
class в Java. Начинът за анализиране на данните е ОК, но не е особено удобен. Второ, ако моята структураfacet_fin_s
притежава друг тип членове (и това е случаят с някои структури от библиотеката, която се опитвам да обвържа), тогава тази стратегия е без значение.Случаят Structure.ByReference: Добрата точка тук е, че получаваме данните като масив от
facet_fin_s
. Това е добра точка за четливостта на кода. За съжаление се връщаме към първия проблем, защото имаме тук, за да използваме този проклетStructure.toArray
за достъп до данните. Тази функция създава копие на паметта от собствената памет в паметта на Java. За голямо количество данни тази функция е наистина бавна.
Има ли наистина някакъв начин да се прочетат данните от собствената памет по много бърз начин и да се запази оригиналната "архитектура", без напълно да се пренаписва Java или C код?
- Продължете да използвате Java класовете, представляващи C структурите
- Избягвайте, доколкото е възможно, пренаписването на много инструменти или класове в Java или C, така че да можем да използваме само JNAerator
- Бърз и четим достъп до основната памет или бързо копиране от основната памет в паметта на Java
Мисля, че се сблъсквам с ограниченията на JNA...