Probleme beim Freigeben von SAFEARRAY



  • Hallo,

    ich habe im c++ Forum-Bereich schon was gepostet und mir
    wurde geraten hier noch mal nachzufragen... Es geht um die Speicherplatzfreigabe
    von einem Safearray was aus einem variant geholt wird... hier der Link
    zu meinem Post: http://www.c-plusplus.net/forum/p2044388#2044388



  • Wenn Du es aus einem Variant holst, dann gibt bitte einfach den Variant mit "VariantClear" frei!



  • Da stimmt so ziemlich gar nichts. Wenn Du SafeArrayUnaccessData aufrufst, sagst Du, dass Du mit dem von SafeArrayAccessData gelieferten Pointer fertig bist und nicht mehr darauf zugreifen willst. Das ist aber nicht das, was Du tatsächlich willst. Dann kannst Du natürlich auch nicht einfach delete auf irgendwelche Pointer aufrufen. Räume Dein VARIANT mit VariantClear auf. Intern wird dann korrekt SafeArrayDestroy aufgerufen was dann bei Bedarf auch SafeArrayDestroyData für Dich aufruft.

    Lese aber am Besten erstmal die Dokumentation zu SAFEARRAYs. Du scheinst eben gar nicht zu wissen, womit Du das hier zu tun hast.



  • Danke für eure Hinweise...

    so in die Richtung hab ich auch schon was gelesen... da hast du vollkommnen recht... ich hab keinen Schimmer mit was ich es hier zu tuen hab ;-)... das Problem is halt, dass der Code nich von mir kommt, ich ihn aber benutzen muss...
    also das mit dem VariantClear hab ich schon mal gelesen.

    Zum einen will die VariantClear Funktion ein VARIANTARG haben
    Wie kann man das konvertieren?
    Und zum Anderen hab ich mal was gelesen, dass bei arrays die
    variantclear funktion nix bringen würde... wenn ich die stelle
    noch mal finde poste ich sie... vlt hab ich das aber auch falsch interpretiert



  • OK...

    ich habe jetzt mal an die Stelle von den deltes

    VariantClear(&res);

    gesetzt...

    und den unaccessdata teil aus der getData auskommentiert...
    muss jetzt mal testen wie der speicher sich verhält

    gebe dann noch mal bescheid



  • also das UnaccessData muss drinbleiben sonst
    kann er den kram scheinbat net löschen...

    das programm läuft auf jeden fall jetzt mal durch...
    nur bin ich mir net so ganz sicher ob der speicher richtig
    freigegeben wird... hab das gefühl als hätte das unter xp
    mit den deletes besser gewirkt...



  • Natürlich kann das Array ohne SafeArrayUnaccessData nicht abgeräumt werden. Aber so, wie Du es machst, ist es schlicht falsch. Du machst doch in etwas dieses hier:

    float* getData(VARIANT in) { 
    
        float HUGEP *out = new float[123];
        delete [] out;
        return out; 
    }
    

    Ohne delete läuft Dir selbstverständlich der Speicher voll, aber was nützt Dir der Pointer nach dem Verlassen der Funktion?



  • ja ich hab schon verstanden, dass das jetzt so ähnlich is wie der code den du gepostet hast. Aber irgendwie scheint es trotzdem zu funktionieren...

    also diese

    env->SetFloatArrayRegion(outArray, 0, peaks, intensities);
    env->SetFloatArrayRegion(outArray, peaks, peaks, masses);
    

    koppieren die daten von intensities und masses in das outarray damit
    dieses an Java zurückgegeben werden kann.

    Also deiner meinung nach müsste ich das Unaccesdata eigentlich direkt vor dem VariantClear machen und nach allen operationen die mit dem array zu tuen haben...
    richtig?

    das tolle is dann nur, dass ich den kompletten code durchgucken muss weil
    derjenige der diesen kram gecodet hat, nutzt diese getData geschichte ja in der
    ganzen DLL... so ein mist.

    aber wieso bekomme ich keine probleme im moment beim zugriff auf das array?
    obwohl es ja mit unaccessdata "unbrauchbar" gekennzeichnet wird?


  • Mod

    SafeArrayAccessData und SafeArrayUnaccessData bilden ein Sandwich.

    D.h.
    1. Du rufst AccessData auf.
    2. Du änderst/benutzt Daten
    3. Du rufst UnaccessData auf.

    Wenn die Get Funktion kein Unaccess aufruft, dann musst Du es dort fixen und nicht bei jedem Aufruf.

    So sollte es es sein!
    Ein Array der gelocked ist kann weder zerstört noch pre Redim bearbeitet werden.



  • Habe den Code jetzt folgendermaßen abgeändert:

    JNIEXPORT jfloatArray JNICALL Java_dbLib_ReadBinaryFile_getSpectrum
      (JNIEnv *env, jclass jc, jstring file, jlong scan, jint func)
    {
    	//COM-Objekt initialisieren
    	CoInitialize(NULL);
    	IDACSpectrumPtr pSpectrum = IDACSpectrumPtr(CLSID_DACSpectrum);
    
    	//Javastrings parsen
    	const char* c_file = env->GetStringUTFChars(file, 0);
    	jfloatArray outArray;
    
    	//benötigte Variablen
    	VARIANT res;
    	long peaks;
    	float *intensities, *masses;
    
    	//Anzahl der Datenpunkte bestimmen und Array initialisieren
    	peaks = getDataPoints(c_file, func, scan);
    	outArray = env->NewFloatArray((int)peaks*2);
    
    	//Daten lesen
    	pSpectrum->GetSpectrum(c_file, func, 0, scan);
    	pSpectrum->get_Intensities(&res);
    	intensities = getData(res);
    	pSpectrum->get_Masses(&res);
    	masses = getData(res);
    
    	//Daten in ein JavaArray kopieren
    	env->SetFloatArrayRegion(outArray, 0, peaks, intensities);
    	env->SetFloatArrayRegion(outArray, peaks, peaks, masses);
    
    	//Aufräumen
    	env->ReleaseStringUTFChars(file, c_file);
    	freeData(res);
    
    	return outArray;
    }
    
    /* Die Methode entpackt ein float-Array aus einem VARIANT*/
    float* getData(VARIANT in) {
    
    	float HUGEP *out;
    	SafeArrayAccessData(in.parray,(void HUGEP**)&out);
    
    	return out;
    }
    
    /* Die Methode räumt einen Variant auf*/
    void freeData(VARIANT in) {
    
    	SafeArrayUnaccessData(in.parray);
    	VariantClear(&in);
    }
    

    Aber der Speicher läuft mir trotzdem voll...
    Irgendwie löscht er das nicht richtig...
    Jemand nen Vorschlag?



  • Ach mist... Ich glaub ich hab da en array vergessen... Muss ich morgen mal testen


  • Mod

    Dein Code kann nicht funktionieren.

    1. Musst Du klären ob get_Intensities und get_Masses ein In/Out oder ein out als Argument nimmt.
    2. SOllte es ein out sein, dann wird der SafeArray des ersten Variants nicht gelöscht. Und Du hast in jedem Fall den letzten Variant nicht freigegeben.
    3. Grundsätzlich musst Du VARIANTs Du Du als Ergebnis bekommen hast mit VariantClear löschen.
    4. Nachdem Du den ertsen VARIANT geholt hat, führt die zweite Verwendung des selben Variants zum Zerstören des ersten VARIANT, dieser Array kann nie freigegeben werden.

    Ich rate Dir dringend etwas mehr über COM zu lernen.



  • vielen dank für eure mühe und auch noch mal für den letzten post...
    das mit dem zweiten variant is mir dann auch gestern erst in den sinn gekommen...
    deswegen sprach ich von nem zweiten array was ich vergessen habe...
    ist halt bissl unglücklich gecodet die dll... vlt hätte ich sie von anfang überabrieten sollen...

    wüsste nicht wieso ich was über com lernen sollte.. finde dafür in der regel keine verwendung. mein projekt ist in java und ich muss halt ne die blöde dll benutzen die schon da is... und jetzt nur extra dafür meine zeit zu opfern mir wetierhin com anzuscheuen sehe ich im moment kein bedarf... 😉

    Also Jemand könnte diesen Thread dann als gelöst markieren....


  • Mod

    ErdyMurphy schrieb:

    wüsste nicht wieso ich was über com lernen sollte.

    Weil Du COM hier extrem benutzt. Ob das nun ene DLL ist oder nich spielt keine Rolle. Und bei COM gibt es Calling Conventions.
    Dazu gehört, dass man ein VARIANT, das man bekommen hat auch brav mit VariantClear freigibt. 😉 oder genauso, dass ein VARIANT mit VariantInit vorblegt wird bevor man es an eine Funktion übergibt (BTW das fehlt in Deinem Code).
    Das wäre nur erlaubt, wenn die Funktion diesen VARANT als out definiert hat.
    Guter Stil ist es immer VariantInit aufzurufen.


Anmelden zum Antworten