2012-03-05 23 views
6

Dado este código C++:JNA pérdida de memoria

void LoadData(char** myVar) 
{ 
    std:: string str("[Really Long String Here]"); 
    unsigned int size = str.length() + 1; 
    *myVar = new char[size]; 
    strncpy(*myVar, str.c_str(), size); 
} 

Y esto Java JNA:

Pointer myVar = new Memory(Pointer.SIZE); 
this.Lib.LoadData(myVar); 
this.someVar = myVar.getPointer(0).getString(0); 

estoy teniendo pérdidas de memoria, tal como lo entiendo, GetPointer (0) debe crear un puntero objeto que debería liberarse en finalize(), pero parece no serlo.

¿Echo de menos algo? Esto parece estar a la altura de las especificaciones ... y puedo ejecutar la función anterior sin fugas en C++ bien.

Llamo el código de Java en un bucle para probar la fuga, he intentado poner pausas, y llamar manualmente al GC, también se hincha a gigabytes bastante rápido de esta manera.

He estado golpeando mi cabeza contra esto durante unos días y le apetece colgarse de algo tan trivial como intentar liberar memoria. Hasta donde puedo decir, solo puedo liberar memoria manualmente en Java si Tengo la dirección, pero no veo cómo podría obtener eso.

Editar:

No importa, ni siquiera creo que hay una manera de hacerlo libre de forma manual a través JNA sin extenderlo ...

Respuesta

3

Añadir esta función a la biblioteca de C++ ...

void FreeData(char** myVar) 
{ 
    delete [] *myVar; 
} 

y luego hacer el código JNA

Pointer myVar = new Memory(Pointer.SIZE); 
this.Lib.LoadData(myVar); 
this.someVar = myVar.getPointer(0).getString(0); 
this.Lib.FreeData(myVar); 

De esta manera se puede asignar y borrar la memoria en C++.

+0

Esto hasta ahora parece funcionar, pero ¿realmente no hay otra manera en JNA de liberar datos? :( – StrangeWill

+1

JNA es solo un contenedor de una biblioteca nativa. No administra la memoria nativa, especialmente el búfer nativo directo. Es la tarea del diseñador de la biblioteca nativa proporcionar interfaces para asignar/desasignar la memoria que usa la biblioteca. – ecle

+1

JNA tiene métodos internos para liberar memoria, simplemente es extraño que tenga que implementarlo de nuevo porque está todo protegido en JNA. – StrangeWill

0

En lugar de miVar = new char [tamaño]

uso

*myVar = malloc(size); 
strncpy(*myVar, str.c_str(), size); 

matrices necesitan ser eliminados como: delete [] * miVar;

JNA prolly no sabe hacer eso.

+1

'strlen (size)'? –

+0

Gracias por el aviso, Niklas, editado. –

+0

Todavía gotea, igual de rápido. :( – StrangeWill

1

Asignar a la persona que llama, no al destinatario.

Por ejemplo:

int LoadData(char* buf, int maxlen) { 
    std:: string str("[Really Long String Here]"); 
    strncpy(buf, str.c_str(), maxlen); 
    if (str.length() < maxlen) 
     return str.length(); 
    return maxlen; 
} 

cuando se llama desde Java, sucedió entonces en un byte[] del tamaño apropiado. Tenga en cuenta que esta implementación es potencialmente muy ineficiente, pero la idea es que generalmente no desea asignar memoria en un contexto y desasignarla en otro.

+1

En implementación: char * buf puede tener 10 bytes, 10k o 150k, posiblemente más una vez que implemente el código completo. Aparte de solo asignar unos pocos megas y simplemente aguantar la implementación ineficiente (mi software puede, pero yo ' estoy más interesado en la _derecha_ forma de hacerlo con JNA). – StrangeWill

+0

Si desea que el destinatario de la llamada administre el almacenamiento, puede devolver un "const char *"; JNA copiará el contenido en una cadena Java, después de lo cual usted seguro para modificar el contenido del buffer y/o eliminarlo.Si devuelve Pointer, puede evitar la copia de memoria hasta que el lado de Java realmente necesite ver los datos. La forma "correcta" de hacerlo depende en gran medida de qué partes (java o nativas) de su programa necesitan acceder a los datos, con qué frecuencia y durante cuánto tiempo vivirá el búfer. – technomage