Best Practices nell'utilizzo risorse in Java

di il
10 risposte

Best Practices nell'utilizzo risorse in Java

Ciao a tutti,
sto programmando in java un'applicazione che, ogni minuto, esegue un blocco di codice.
Dopo un giorno di test ho notato che l'uso della RAM, tende ad aumentare e non a mantenersi stabile.
Come posso creare un programma che possa funzionare h-24 7 Giorni su 7, senza che l'uso della RAM sia in continuo aumento? Quali sono le Best Practices per riuscire nel mio intento? Ho provato a mettere a null tutte le variabili (Stringhe, ArrayList, ecc) e i riferimenti agli oggetti instanziati e non più utilizzati, ma senza grossi risultati.
Grazie mille
Joe Joe

10 Risposte

  • Re: Best Practices nell'utilizzo risorse in Java

    Hai fondamentalmente due situazioni possibili:

    1) l'aumento di memoria e' legato SOLTANTO al fatto che Java ha memoria disponibile, e quindi non ha la necessita' di chiamare il Garbage Collector. Soluzione: forza la chiamata del GC ogni tot minuti (ad esempio mediante un thread o un timer)

    2) hai dei MEMORY LEAK, cio'e la tua applicazione, o le librerie che usi, allocano delle strutture dati che poi non rilasciano. Il fatto che non le rilascino puo' essere docuto a due fattori:

    2.1) la libreria ha dei bug: se lo scopri, corregilo, oppure cambia libreria
    2.2) non usi la libreria nel modo corretto, nel senso che una volta usata, devi anche dire che hai finito di usarla. Noaturalmente non c'e' una regola generale, ma dipende da libreria a libreria. Devi studiare la documentazione

    Se e' la tua applicazione a non rilasciare le risorse, allora sono c..i amari: devi scoprire dove questo avviene.

    In generale, a meno di applicazioni particolarmente semplici, e' un lavoraccio decisamente complicato.

    A supporto, comunque, ci sono i Memory Profiler, come JProfiler, YourKit, e altri li trovi qui:

    https://blog.idrsolutions.com/2014/06/java-performance-tuning-tools/
  • Re: Best Practices nell'utilizzo risorse in Java

    Ciao @migliorabile, ti ringrazio per la tua risposta.
    Potresti cortesemente mostrarmi con un esempio, come forzare la GC?
    Come faccio a dire che ho terminato di utilizzare la libreria? Io metterei a null la variabile che referenzia l'oggetto.
    Nel frattempo, installo uno dei tool che mi hai indicato.
    Grazie
  • Re: Best Practices nell'utilizzo risorse in Java

    Google ti da tutte le risposte: basta impegnarsi e non aspettare la pappa pronta

    https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html (.gc())

    Per la libreria: dipende dalla libreria.

    In ogni caso, non ti serve a nulla SCARICARE la libreria (cioe' rimuovere dalla memoria le classi) perche' NON E' IL CODICE da eseguire che da problemi (se e' 1MB, rimarra' 1MB fino alla fine del tempo) ma le strutture dati che con la libreria hai creato.
  • Re: Best Practices nell'utilizzo risorse in Java

    Ti ringrazio, ho trovato come forzare la GC.
    Le mie domande sono per i posteri che avranno i miei stessi dubbi A parte gli scherzi, grazie.
    Ora controllerò tutto il codice cercando il punto dove non rilascio le risorse (mettendo null gli oggetti e variabili istanziate e non più utili).
  • Re: Best Practices nell'utilizzo risorse in Java

    Ciao @migliorabile,
    ho installato VisualVM e nel codice, ho forzato la GC. Ho constato che la memory Heap si mantiene su valori costanti, mentre il processo javaw.exe, creasce di continuo. Hai qualche altro suggerimento per risolvere il mio problema?
    Il codice interroga ogni 5 secondi una risorsa esterna ed il codice è così:
    public static void main(String argv[]) throws ParserConfigurationException {
    		preCaricamento();
    		while(true){
    			executor();
    			try {
    				Thread.sleep(5000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
            private static void preCaricamento(){
                   ... operazioni....
                   variabile_1=null;
                   .....
                   variabile_n=null;
                   System.gc();
            }
            private static void executor(){
                  getRemoteValue......
                  writeValueIntoDB.....
                   variabile_1=null;
                   .....
                   variabile_n=null;
                   System.gc();
            }

    VisualVM.PNG
    VisualVM.PNG


    SnapShotMemoryUse.png
    SnapShotMemoryUse.png

  • Re: Best Practices nell'utilizzo risorse in Java

    Dai diagrammi e' ovvio che hai un memory leak, cioe' ci sono strutture dati che vengono allocate e non piu' rilasciate.

    Naturalmente NON E' un problema della dimensione dello HEAP: quella e' costante, lo configuri in fase di lancio della VM Java, e comunque e' gestita dalla VM stessa.

    Il problema e' la linea seghettata sopra l'area verdolina, che aumenta con il tempo! Cioe' la quantita' di memoria EFFETTIVAMENTE allocata e non rilasciabile dal GC.

    E non lo puo' fare perche' gli oggetti sono oggetti ATTIVI, cioe' ACCESSIBILI dall'applicazione.

    E queste strutture dati coinvolgono dei byte array (byte[]).

    Ora, i memory profile ti permettono di analizzare la memoria partendo da un oggetto qualunque e seguento i reference in avanti (quali oggetti ,l'oggetto osservato, contiene) e all'indietro (chi sono gli oggetto che contengono l'oggetto osservato).

    Fa anche un'altra cosa, e' in grado di raggruppare gli oggetti per 'classe'.

    Ora quello che devi fare e' come con le briciole di pane di Pollicino: partendo dai byte[] (oggetto primitivo, che non contiene reference ad altri oggetti) e seguendo i reference all'indietro, tentare di scoprire quali oggetti stanno allocando i byte array (o ricorsivamente, quali oggetti allocano oggetti che allocano i byte array, quali oggetti allocano oggetti che allocano oggetti che allocano byte array, e cosi' via )

    Quindi, una volta capito chi sono questo oggetti, capire perche' vengono allocato e non rilasciati.

    Diciamo che al 99% e' un problema di implementazione PARZIALE di qualche TUO pezzo di codice.
    Al 1% ci potrebbe essere un problema in una delle librerie che usi.

    Una buona dritta puo' essere quella di confrontare DUE snapshot abbastanza distanti tra loro, in modo che l'aumento di memoria sia sufficientemente evidente, ma abbastanza lontani dall'inizio dell'esecuzione dell'applicazione, per avere una situazione stabile in termini di oggetti allocati un numero predefinito di volte (e che non cambia piu' nel tempo).

    Non ci sono metodi miracolosi: e' una vera e propria caccia al tesoro.
    O se vuoi, e' come cercare il colpevole di un delitto avendo a disposizione solo degli indizi.
  • Re: Best Practices nell'utilizzo risorse in Java

    Ciao @migliorabile,
    ho rivisitato completamente il mio codice, ma non ho avuto grandi giovamenti. Inoltre non mi spiego i vettori Byte[] char[] e int[], i quali non sono presenti nel mio codice.
    Per caso tu conosci la libreria JAMOD? Possono essere variabili di tale libreria, le quali non vengono rilasciate?
    Grazie.
  • Re: Best Practices nell'utilizzo risorse in Java

    Certo che sono presenti nel tuo codice!
    Non c'e' SOLO il tuo codice in esecuzione, ma anche la libraria Java!

    Ad esempio: String usa char[], i vari tipi di Stream usano dei byte[] come buffer, ecc.

    Devi usare il MemoryProfiler, e' l'unica strada per capire che cosa e' che non va.
  • Re: Best Practices nell'utilizzo risorse in Java

    Joe Joe ha scritto:


    Inoltre non mi spiego i vettori Byte[] char[] e int[], i quali non sono presenti nel mio codice.
    Non sono presenti nel tuo codice .... ma sono sicuramente creati dal framework o dalle eventuali librerie utilizzate. Potrebbero essere array di "buffer" interni, potrebbero essere array "costanti" (con valori che non cambiano), ecc... E tutto questo CONTA all'interno di una istanza della JVM.
  • Re: Best Practices nell'utilizzo risorse in Java

    Su quello avete ragione, in quanto ho spulciato un pò le Interface della Libreria, e sono presenti per l'appunto Vettori di byte e quant'altro.
    Io stò utilizzando la libreria Jamod, e ogni 1000ms interrogo una periferica. Il tutto è così fatto:
    while(true){
                //...Eseguo la richiesta
                //...Prelevo la risposta
                //...Stampo il contenuto
    }
    
    Qualcuno di voi ha esperienza con la Libreria Jamod e mi sà aiutare nel risolvere il mio problema.
    Grazie
Devi accedere o registrarti per scrivere nel forum
10 risposte