Newsgroup: it.comp.java
Titolo: Gestione Garbage collection

Ciao a tutti
 io ho la necessita' di creare un'applicazione web (con servlet runner che
gira sopra Xitami web server) che deve girare anche su macchine molto
retrodatate (es. win98+32mb di ram). C'e' un modo per configrare la
garbage collection della mia jvm o vedere che impostazioni ha? ho notato
che la mia applicazione (allo stato primordiale;) ) non libera risorse,
anzi cresce sensibilmente in memoria (che si autoriproduca??;) )
Grazie  a chiunque possa darmi qualche consiglio.
Ciao
Jonny
Spedito da 
http://www.submission.it
promuovi gratis il tuo sito web sui motori di ricerca

 Grazie  a chiunque possa darmi qualche consiglio.
Secondo me hai fatto qualche errore di programmazione...
sei sicuro che il tuo programma non crei oggetti che in realta' non servono?

 ha scritto nel messaggio
news:aabqpp$7le$1...@atlantis.cu.mi.it...


 garbage collected producendo un memory leak.
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 ha scritto nel messaggio
news:080d7de412d05c1611d...@mygate.mailgate.org...


 dei memory leak.
Si, pero' tieni a mente che gli errori non sono solo i tuoi (vedi
bachi in jdk ed in eventuali altre librerie) e debuggare il codice di
altri, specie se non di dimensioni ridicole, non e' il massimo della
vita.
-- 
Bye,
  Mirko

 dell'uso dell'operatore '+'. (con jdk 1.3.1)
Scusami, ma non ci credo..... non so che test tu abbia fatto.... potresti
postare le caratteristiche del test???

L'ho scritto alla svelta e spero di non aver fatto strafalcioni. Comunque
qualunque test tu faccia i risultati non possono che essere simili a questi:
Testing 10000 cicli...
Test Concatenazione String
    Tempo: 741 ms
    Memoria: 520704
Test Append StringBuffer
    Tempo: 0 ms
    Memoria: 74064
Il risultato dell'elaborazione č uguale? true
Testing 20000 cicli...
Test Concatenazione String
    Tempo: 2884 ms
    Memoria: 195424
Test Append StringBuffer
    Tempo: 0 ms
    Memoria: 147800
Il risultato dell'elaborazione č uguale? true
Testing 30000 cicli...
Test Concatenazione String
    Tempo: 6820 ms
    Memoria: 379136
Test Append StringBuffer
    Tempo: 10 ms
    Memoria: 147800
Il risultato dell'elaborazione č uguale? true
Testing 40000 cicli...
Test Concatenazione String
    Tempo: 13790 ms
    Memoria: 899808
Test Append StringBuffer
    Tempo: 0 ms
    Memoria: 295264
Il risultato dell'elaborazione č uguale? true
Testing 50000 cicli...
Test Concatenazione String
    Tempo: 24445 ms
    Memoria: 1599952
Test Append StringBuffer
    Tempo: 10 ms
    Memoria: 295264
Il risultato dell'elaborazione č uguale? true
Tenete conto che il valore indicato come consumo di memoria  non č
assolutamente attendibile, poiché nell'elaborazione puň succedere che sia
girato (anche piů volte) il garbage collection liberando quindi la memoria.
E' giusto un'informazione indicativa. Il valore del tempo di elaborazione
invece dovrebbe essere abbastanza attendibile.
ecco il codice utilizzato per eseguire il "benchmark".
public class StringBufferTest {
    public int numeroCicli;
    public String testString() {
        System.out.println("Test Concatenazione String");
        String s = "";
        Runtime.getRuntime().gc();
        long mi = Runtime.getRuntime().freeMemory();
        long ti = System.currentTimeMillis();
        for (int i = 0; i < numeroCicli; i++) {
            s += "a";
        }
        System.out.println("\tTempo: " + (System.currentTimeMillis() - ti) +
" ms" );
        System.out.println("\tMemoria: " + (mi -
Runtime.getRuntime().freeMemory() ));
        return s;
    }
    public String testStringBuffer() {
        System.out.println("Test Append StringBuffer ");
        StringBuffer sb = new StringBuffer();
        Runtime.getRuntime().gc();
        long mi = Runtime.getRuntime().freeMemory();
        long ti = System.currentTimeMillis();
        for (int i = 0; i < numeroCicli; i++) {
            sb.append("a");
        }
        System.out.println("\tTempo: " + (System.currentTimeMillis() - ti) +
" ms" );
        System.out.println("\tMemoria: " + (mi -
Runtime.getRuntime().freeMemory() ));
        return sb.toString();
    }
    public void doTests() {
        System.out.println("Testing " + numeroCicli + " cicli...");
        String s1 = testString();
        String s2 = testStringBuffer();
        System.out.println("Il risultato dell'elaborazione č uguale? " +
s1.equals(s2) + "\n");
    }
    public static void main(String[] args) {
        StringBufferTest sbTest = new StringBufferTest();
        for (sbTest.numeroCicli = 10000;
             sbTest.numeroCicli <= 50000;
             sbTest.numeroCicli += 10000) {
            sbTest.doTests();
        }
    }
}
Ovviamente, spero che nessuno sia abbastanza folle da utilizzare "+" per
fare la concatenazione di 50.000 stringhe...  e in molti casi l'overhead
dell'operazione di concatenazione č trascurabile. Comunque ciň non toglie
che sia una buona pratica usare il codice piů performante, IHMO.
Jigi

 postare le caratteristiche del test???
Il test l'ho fatto tempo fa (6 mesi) sulla nostra applicazione desktop
(swing) quando mi sono occupato della sua ottimizzazione e della
riduzione degli out of memory.
Non ti posso dire granche' in quanto l'app non e' mia e non e' stata
ancora rilasciata, comunque attualmente per la gc uso i paramentri di
default ed allo start occupa +o- 8M di 11M allocati.
La parte interessata riguarda la sezione parser/importazione di file
ascii (di qualche mega) in un db (interbase o db2) e relativo report
finale di eventuali errori verificatisi.
Col file di test questa fase impiegava piu' o meno 15 min nella
versione originale (operatore '+') e circa 1-2 min in piu' con l'uso
di StringBuffer. Cronometrati a mano, mentre guardando i tempi
parziali di OptimizeIt avrei dovuto avere un miglioramento delle
prestazioni.
I test sono stati effettuati su NT (300M) e 2000 (512M) con jdk sun.
Ovviamente in questo specifico caso, non e' detto che in altri si
ottengano gli stessi risultati.
-- 
Bye,
  Mirko

ottengano gli stessi risultati.
mmm...
codice originale:
    public static void main(String args[]) {
        String a = "stringa a ";
        String b = "stringa b ";
        String c = String.valueOf(a) + String.valueOf(b);
        System.out.println(c);
    }
codice decompilato (con JVM istructions):
    public static void main(String args[])
    {
        String a = "stringa a ";
    //    0    0:ldc1            #3   <String "stringa a ">
    //    1    2:astore_1
        String b = "stringa b ";
    //    2    3:ldc1            #4   <String "stringa b ">
    //    3    5:astore_2
        String c = String.valueOf(a) + String.valueOf(b);
    //    4    6:aload_1
    //    5    7:invokestatic    #5   <Method String String.valueOf(Object)>
    //    6   10:invokestatic    #5   <Method String String.valueOf(Object)>
    //    7   13:aload_2
    //    8   14:invokestatic    #5   <Method String String.valueOf(Object)>
    //    9   17:invokestatic    #5   <Method String String.valueOf(Object)>
    //   10   20:invokevirtual   #6   <Method String String.concat(String)>
    //   11   23:astore_3
        System.out.println(c);
    //   12   24:getstatic       #7   <Field PrintStream System.out>
    //   13   27:aload_3
    //   14   28:invokevirtual   #8   <Method void
PrintStream.println(String)>
    //   15   31:return
    }
come si vede la concatenazione avviene chiamando il metodo
String.concat(String):
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        char buf[] = new char[count + otherLen];
        getChars(0, count, buf, 0);
        str.getChars(0, otherLen, buf, count);
        return new String(0, count + otherLen, buf); <-- nuovo oggetto.
    }
Poi se ci sono compilatori più furbi non lo so, ma questo è il codice
prodotto da quello di JBuilder 6.
A tatto... mi sembra molto dispendioso più dispendioso di un append, visto
che gli oggetti String sono per definizione "immutabili", e qualsiasi
variazione implica la creazione di un nuovo oggetto. StringBuffer serve
proprio a contenere Stringhe che necessitano di essere cambiate; non vedo
perché dovrebbe essere più pesante, se serve proprio a rendere più efficace
la manipolazione delle Stringhe.
Se qualcuno ha un pezzo di codice che mi dimostra il contrario, sarei
felicissimo di studiarlo.
Luigi.

Grazie per le spiegazioni....
Ciao 
Luca


Ciao Jigi,
volevo chiederti come hai fatto ad ottenere il codice decompilato, con VAJ
si riesce ad ottenere?
Inoltre in una mia WebApp che gira sotto WebSphere ottengo spesso
OutOfMemory.
Come mi consigli di procedere per vedere dove potrebbe stare il problem?
ciao

 OutOfMemory.
Dovresti prima di tutto isolare la parte del codice che genera il problema,
quindi verificare che non ci siano sprechi, o se è possibile riutilizzare le
stesse istanze anziché crearne di nuove. In alcuni caso l'out of memory è
inevitabile: una volta un mio collega mi ha fatto vedere del codice che
tirava su qualche decina di migliaia di record dal DB e lo manteneva in un
Vector che poi serializzava d'un botto verso un altra VM... ovvio che in
casi come questi, se è proprio necessario avere in memoria tutti questi dati
in un botto non è che si possa fare gran che (anche se gli oggetti potevano
essere trasferiti un gruppo alla volta, anziché tutti insieme). Quando la
memoria non basta, si può pensare di spostare questi oggetti dalla RAM in
uno storage su disco o su database (su cui eventualmente poi eseguire
operazioni come un ordinamento è molto meno dispendioso con una query). In
quel caso specifico l'out of memory avveniva quando, dopo aver tirato su un
botto di dati dal db, poi lo serializzava per spedirlo via rete; ma si
trattava di un errore concettuale: non si può pensare che un applicazione
(web) faccia delle cose del genere, a meno di non pensare che l'utente lasci
il pc acceso un paio di settimane per poter vedere la pagina finalmente nel
suo browser...
Dovresti cominciare a vedere *dove* va in out of memory il tuo programma e
capire perché, quindi regolarti di conseguenza. Non c'è una risposta unica
per tutti i problemi di out of memory. Prova a raccontarci *perché* il tuo
programma va in out of memory e forse qualcuno può darti il consiglio
giusto.
Con EJB un errore comune è quello di utilizzare dei finder selvaggemente:
per esempio, se va in out of memory perché esegui delle findAll su una
tabella da un milione di record, beh, potresti cominciare a pensare di
utilizzare un sessionbean che preleva solo i dati che gli servono anziché
istanziare una quantità enorme di entity; o pensare di trasferire i dati un
po' per volta dal db alla memoria e non trattarli tutti insieme.
Ma nessuno ti può indicare perché il tuo programma va in out of memory senza
sapere cosa fa...
Ci sono programmi che possono profilare il consumo di memoria di ogni linea
del codice del tuo programma (solo che costano un sacco di $$$) dai uno
sguardo al sito di compuware/numega.
ciao
Luigi