2012-03-05 6 views
6

Dato questo codice C++:JNA Perdita di 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); 
} 

E questo JNA Java:

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

sto avendo problemi di memoria, se ho capito bene, getPointer (0) dovrebbe creare un puntatore oggetto che dovrebbe essere rilasciato su finalize(), ma sembra non esserlo.

Mi manca qualcosa? Questo sembra su specifica ... e posso eseguire la funzione di cui sopra senza perdite in C++ bene.

Io chiamo il codice Java in un ciclo per testare la perdita, ho provato a mettere in pausa, e manualmente chiamando il GC, inoltre si gonfierà in gigabyte piuttosto rapidamente in questo modo.

Ho sbattuto la testa contro questo per alcuni giorni e mi fa schifo rimanere impiccato a qualcosa di così banale come tentare di liberare memoria. Per quanto posso dire posso liberare solo manualmente la memoria in Java se Ho l'indirizzo, ma non riesco a vedere come lo otterrei.

Edit:

Nevermind, non so nemmeno credo che ci sia un modo per farlo manualmente gratuitamente attraverso JNA senza estenderla ...

risposta

3

aggiungere questa funzione alla libreria C++ ...

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

e poi fare questo codice JNA

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

In questo modo si alloca e cancellare la memoria in C++.

+0

Finora sembra funzionare, ma non c'è davvero nessun altro modo in JNA per liberare i dati? :( – StrangeWill

+1

JNA è solo un wrapper per una libreria nativa e non gestisce la memoria nativa, in particolare il buffer nativo diretto.È compito del progettista della libreria nativa fornire interfacce per allocare/deallocare la memoria utilizzata dalla libreria. – ecle

+1

JNA ha metodi interni per liberare memoria, solo strano che dovrei implementarlo di nuovo perché è tutto protetto in JNA. – StrangeWill

0

Invece di myVar = new char [size]

uso

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

Array devono essere cancellati come: delete [] * myVar;

JNA prolly non sa farlo.

+1

'strlen (size)'? –

+0

Grazie per l'heads-up, Niklas, curato. –

+0

Ancora perdite, altrettanto rapidamente. :( – StrangeWill

1

Assegnare al chiamante, non al chiamato.

Ad esempio:

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; 
} 

Poi quando si chiama da Java, passare in un byte[] di dimensioni adeguate. Si noti che questa implementazione è potenzialmente molto inefficiente, ma l'idea è che generalmente non si desidera allocare memoria in un contesto e trasferirla in un'altra.

+1

Nell'implementazione: char * buf può essere di 10 byte, 10k o 150k, possibilmente di più una volta implementato il codice completo, oltre ad allocare pochi meg e sopportare l'implementazione inefficiente (il mio software può, ma io m più interessato al modo _right_ di farlo con JNA.) – StrangeWill

+0

Se vuoi che il callee gestisca l'archiviazione, puoi restituire un "const char *"; JNA copierà il contenuto in una stringa Java, dopo di che sarai sicuro di modificare il contenuto del buffer e/o cancellarlo.Se si restituisce puntatore, è possibile evitare la copia di memoria fino a quando il lato Java ha effettivamente bisogno di guardare i dati. Il modo "giusto" per farlo dipende molto da quali parti (java o native) del tuo programma devono accedere ai dati, con quale frequenza e per quanto tempo il buffer vivrà. – technomage