Come memoria profilo in Java?

Sto ancora imparando le corde di Java così dispiaciuto se c’è una risposta ovvia a questo. Ho un programma che sta prendendo un sacco di memoria e voglio immaginare un modo per ridurne l’utilizzo, ma dopo aver letto molte domande su SO ho l’idea che ho bisogno di provare dove si trova il problema prima di iniziare a ottimizzarlo.

Quindi ecco cosa ho fatto, ho aggiunto un punto di interruzione all’inizio del mio programma e l’ho eseguito, quindi ho avviato visualVM e ho avuto il profilo della memoria (ho anche fatto la stessa cosa in netbeans solo per confrontare i risultati e sono gli stessi ). Il mio problema è che non so come leggerli, ho ottenuto l’area più alta solo dicendo char[] e non riesco a vedere alcun codice o altro (il che ha senso perché visualvm si connette a jvm e non può vedere il mio fonte, ma anche netbeans non mi mostra la sorgente come fa quando si fa il profiling della cpu).

Fondamentalmente quello che voglio sapere è quale variabile (e spero più dettagli come in quale metodo) viene utilizzata tutta la memoria, così posso concentrarmi a lavorare lì. C’è un modo semplice per farlo? In questo momento sto usando eclipse e java per sviluppare (e installato visualVM e netbeans appositamente per la profilazione, ma sono disposto a installare qualsiasi altra cosa che ritieni possa svolgere questo lavoro).

EDIT: Idealmente, sto cercando qualcosa che prenderà tutti i miei oggetti e li ordinerà per dimensione (così posso vedere quale è la memoria hogging). Attualmente restituisce informazioni generiche come string [] o int [] ma voglio sapere a quale object si riferisce in modo che possa lavorare per ottenere le sue dimensioni più ottimizzate.

    Le stringhe sono problematiche

    Fondamentalmente in Java, i riferimenti alle String (le cose che usano char[] dietro le quinte) domineranno la maggior parte delle applicazioni di business in termini di memoria. Il modo in cui vengono creati determina la quantità di memoria che consumano nella JVM.

    Solo perché sono così fondamentali per la maggior parte delle applicazioni aziendali come un tipo di dati, e sono anche una delle più affamate di memoria. Questa non è solo una cosa di Java, i tipi di dati String occupano molta memoria in praticamente ogni linguaggio e libreria di run-time, perché almeno sono solo array di 1 byte per carattere o in peggio (Unicode) sono array di più byte per carattere.

    Una volta durante la profilazione dell’utilizzo della CPU su un’app Web che aveva anche una dipendenza JDBC Oracle, ho scoperto che StringBuffer.append() dominava i cicli della CPU di molti ordini di grandezza su tutte le altre chiamate di metodi combinate , molto meno qualsiasi altra chiamata al metodo singolo. Il driver JDBC ha fatto molta e molta manipolazione delle String , una sorta di compromesso sull’uso di PreparedStatements per tutto.

    Ciò che ti preoccupa di te non può controllare, non direttamente comunque

    Quello su cui dovresti concentrarti è quello che hai nel controllo, che è quello di assicurarti di non conservare i riferimenti più a lungo del necessario, e di non duplicare le cose inutilmente. Le routine di raccolta dei dati inutili in Java sono altamente ottimizzate e, se si impara come funzionano i loro algoritmi, è ansible assicurarsi che il programma si comporti in modo ottimale affinché tali algoritmi funzionino.

    Java Heap Memory non è come la memoria gestita manualmente in altre lingue, quelle regole non si applicano

    Le perdite di memoria considerate in altri linguaggi non sono la stessa cosa / causa principale come in Java con il suo sistema di garbage collection.

    Molto probabilmente nella memoria Java non viene consumato da un singolo object uber che perde (riferimento ciondolante in altri ambienti).

    È molto probabile che ci siano molte allocazioni più piccole a causa degli oggetti StringBuffer / StringBuilder non dimensionati in modo appropriato nelle prime istanze di installazione e che quindi devono crescere automaticamente gli array char[] per contenere le chiamate append() successive.

    Questi oggetti intermedi possono essere tenuti più a lungo del previsto dal garbage collector a causa dell’ambito in cui si trovano e molte altre cose che possono variare in fase di esecuzione.

    ESEMPIO: il garbage collector può decidere che ci sono candidati, ma perché ritiene che ci sia ancora molto spazio in memoria che potrebbe essere troppo dispendioso in termini di tempo per eliminarli in quel momento, e aspetterà fino alla memoria la pressione diventa più alta.

    Il garbage collector è davvero buono ora, ma non è magico, se stai facendo cose degenerate, questo farà sì che non funzioni in modo ottimale. C’è molta documentazione su internet sulle impostazioni del garbage collector per tutte le versioni delle JVM.

    Questi oggetti non referenziati potrebbero non aver raggiunto il tempo in cui il garbage collector pensa di averne bisogno per farli cancellare dalla memoria, o potrebbero esserci riferimenti ad altri oggetti ( List ) ad esempio che non si fa ‘ t realizziamo ancora punti per quell’object. Questo è quello che viene più comunemente indicato come perdita in Java, che è una perdita di riferimento più specificatamente.

    ESEMPIO: se sai che devi creare una String 4K usando un StringBuilder con una new StringBuilder(4096); non il default, che è come 32 e inizierà immediatamente a creare garbage che può rappresentare molte volte quello che pensi che l’object debba essere dimensionato.

    Puoi scoprire quanti di quali tipi di oggetti sono istanziati con VisualVM, questo ti dirà cosa devi sapere. Non ci sarà un solo lampeggiante che punta a una singola istanza di una singola class che dice “Questo è il grande consumatore di memoria!”, Cioè a meno che non ci sia una sola istanza di qualche char[] che tu sia leggendo alcuni file di grandi dimensioni, e anche questo non è ansible, perché molte altre classi usano char[] internamente; e quindi lo sapevi già.

    Non vedo alcuna menzione di OutOfMemoryError

    Probabilmente non hai un problema nel tuo codice, il sistema di garbage collection potrebbe non essere sottoposto a una pressione sufficiente per dare il via e deallocare gli oggetti che ritieni debbano essere ripuliti. Probabilmente ciò che pensi non è un problema, a meno che il tuo programma non si blocchi con OutOfMemoryError . Questo non è C, C ++, Objective-C o qualsiasi altra lingua / runtime di gestione della memoria manuale. Non puoi decidere cosa è in memoria o meno al livello di dettaglio che ti aspetti che dovresti essere in grado di fare.

    In JProfiler , puoi andare al walker dell’heap e triggersre la vista degli oggetti più grandi. Vedrai gli oggetti che conservano più memoria. La memoria “trattenuta” è la memoria che verrebbe liberata dal garbage collector se si rimuovesse l’object.

    È quindi ansible aprire i nodes dell’object per vedere l’albero di riferimento degli oggetti mantenuti. Ecco una schermata della vista object più grande:

    inserisci la descrizione dell'immagine qui

    Disclaimer: la mia azienda sviluppa JProfiler

    Consiglierei di catturare i dump dell’heap e usare uno strumento come Eclipse MAT che ti permetta di analizzarli. Ci sono molti tutorial disponibili. Fornisce una vista dell’albero del dominatore per fornire informazioni sulle relazioni tra gli oggetti sull’heap. Specificamente per quello che hai menzionato, la funzione “path to GC roots” di MAT ti dirà dove si fa riferimento alla maggior parte degli oggetti char [], String [] e int []. JVisualVM può anche essere utile per identificare perdite e allocazioni, in particolare utilizzando le istantanee con tracce dello stack di allocazione. Ci sono alcuni passaggi del processo per ottenere le istantanee e confrontarle per trovare il punto di allocazione.

    Java JDK viene fornito con JVisualVM sotto la cartella bin, una volta che il server delle applicazioni (ad esempio è in esecuzione) è ansible eseguire visualvm e collegarlo all’host locale, che fornirà l’allocazione della memoria e consentirà di eseguire il dump dell’heap

    inserisci la descrizione dell'immagine qui

    Per ulteriori dettagli su come abilitare: http://sysdotoutdotprint.com/technologies/java/6

    Se si utilizza visualVM per controllare l’utilizzo della memoria, si concentra sui dati, non sui metodi. Forse i tuoi dati big char [] sono causati da molti valori di stringa? A meno che non si stia utilizzando la ricorsione, i dati non saranno da variabili locali. In questo modo puoi concentrarti sui metodi che inseriscono elementi in strutture di dati di grandi dimensioni. Per scoprire quali dichiarazioni precise causano la tua “perdita di memoria”, ti suggerisco in aggiunta

    • leggi Josh Bloch’s Effective Java Item 6: (Elimina riferimenti a oggetti obsoleti)
    • utilizzare un framework di registrazione e creazioni di istanze di registro al livello di massima verosimiglianza.