2014-04-14 22 views
5

Sto lavorando su un vecchio programma java che include una libreria nativa con chiamate Fortran.perdita di memoria java con codice nativo

Quindi, ho Java che chiama C tramite JNI, quindi chiama Fortran.

In produzione ci sono un errore di memoria come:

allocazione di memoria Native (malloc) non è riuscito a destinare 120000 byte per jfloat in C: \ BUILD_AREA \ jdk6_37 hotspot \ src \ share \ \ vm \ prim \ jni.cpp

Sospetto che si tratti di una perdita di memoria.

Sono nuovo in azienda, e mi piacerebbe lavorare su linux ma mi fanno lavorare su Windows :( In produzione stiamo usando il file .so perché siamo su solaris, e io uso DLL su Windows (logico.)

In primo luogo, ho provato a riprodurre il problema di produzione, quindi ho creato un test unitario che carica la DLL e chiama la classe java che chiama il metodo nativo molte volte Quando l'ho fatto, ho visto con processExplorer.exe che la memoria è cresciuta fino a 2 MB ogni 2 secondi e ho un'eccezione come nella produzione

Sono felice di aver riprodotto correttamente il problema, e ho potuto dire che il problema è venuto dal codice C o Fortran.

Successivamente, ho cercato di rimuovere la chiamata a Fortran, e la mia Java solo chiamato C (senza Fortran, questo test mi ha permesso di vedere se il problema veniva dalla C o Fortran.)

E il risultato è stato che la memoria non si è mossa! Freddo! Potrei dire che non ho avuto alcun problema con malloc/free in C.

Così, ho deciso di imparare un po 'di Fortran a guardare attraverso il codice. :)

Ho imparato che in Fortran possiamo usare le parole chiave allocate e deallocate per giocare con la memoria. E il mio codice non contiene queste parole chiave. :(

Dopo tutto questo, qualcuno mi dia l'accesso su Solaris per lanciare il mio test JUnit che chiama Java-> JNI-> C => Fortran e di utilizzare la .so invece di DLL.

E sorpresa - la memoria non si mosse !!! non ho alcun problema sotto Solaris o RedHat

sono bloccato perché il problema esiste sulla produzione, ma non riesco a riprodurre chiaramente :(

..

Perché vedo una differenza tra DLL e SO? Il codice (java/C/Fortran) è esattamente lo stesso perché sono io a compilarlo.

Come posso indagare di più?

Ho provato a fare un dump della memoria in Windows in cui ho riprodotto il problema, ma non vedo nulla.

Il problema è nella jvm? Oppure il problema può essere nell'oggetto passato a C tramite JNI?

Grazie mille per avermi aiutato con questo problema.

Info: Sto utilizzando Windows 7 64bit

PS: Sono francese, quindi scusate il mio inglese. Cerco di fare del mio meglio ogni volta. ;)

Ecco l'intestazione f codice C:

#ifndef unix 
     __MINGW_IMPORT void modlin_OM(float pmt[], float abaque[][], float don[][], float cond[], float res[][], int flag[]) ; 
    #else 
     extern void modlin_om_(float * pmt, float * abaque, float * don, float * cond, float * res, int * flag) ; 
    #endif 

e dopo il metodo:

JNIEXPORT jint JNICALL Java_TrtModlin_modlin_1OM 
    (JNIEnv * env, jobject obj, 
jfloatArray pmtPar, 
jobjectArray abaquePar, jobjectArray donPar, jfloatArray condPar, jobjectArray resPar, jintArray flagPar) 
    { 

codice, e la chiamata al metodo per FORTRAN

#ifndef unix 
     modlin_OM(pmt, abaque, don, cond, res, & iFlag) ; 
    #else 
modlin_om_(pmt, abaque, don, cond, res, & iFlag) ; 
    #endif 

Come ho detto prima, provo la chiamata a C rimuovendo queste righe e t La memoria non è cresciuta :(Eseguo un test rimuovendo una riga con free (someVar) e la memoria cresce perché free non è fatto in questo caso. Ecco perché concludo che il mio C era ok con Free/Malloc.

+1

E avete la fonte di questi collegamenti C per entrambe le piattaforme (Unix e Windows)? – fge

+0

sì ho il sorgente ma è lo stesso per Windows o Unix, lo aggiungo alla fine della mia domanda (se vuoi tutto il sorgente, posso darti se vuoi) –

+0

quale compilatore fortran? – Peter

risposta

1

Analizzare un problema di memoria è sempre complesso. Dalla mia esperienza ci sono due modi:

1) Si tenta di riprodurre. Questo suppone che tu abbia il codice sorgente e un'idea della causa principale. 2) Si osservano i crash di produzione: la frequenza, la correlazione con altri eventi, ecc.

Questo può aiutare a determinare se si tratta di una perdita di memoria o meno (potrebbe essere un alto consumo sotto un carico di lavoro .. .)

Nel tuo caso particolare, ho notato i seguenti punti:

  1. Il comportamento del codice può essere diverso su differenti sistemi operativi. È molto raro per il codice Java (bug JVM). È frequente con codice nativo (ad esempio, dimentica di chiudere un ZIP causa una perdita di memoria su Linux ma non su Windows ...)

  2. Nella tua intestazione C (* .h): abaque, don e res sono 'float * *' su Windows e 'float *' su Unix. Potrebbe essere un bug nelle intestazioni C, o significa le implementazioni C non si aspettano gli stessi tipi di argomenti a seconda del sistema operativo (che è strano per me ...)

Nel secondo caso, il fatto di compilare le intestazioni C su Windows (che non è il target) potrebbe spiegare che non si generano stub JNI corretti (tipico problema di compilazione incrociata) ... Da qui possiamo fare molte ipotesi, semplici o molto complesse ..

Buona fortuna!