2016-05-19 43 views
5

Proverò in breve a spiegare il problema. Lavoro nel dominio della supply chain in cui trattiamo articoli/prodotti e SKU.Scarse prestazioni dovute al garbage collector Java? Ho bisogno di suggerimenti

Dire che il mio intero problema è di 1 milione di SKU e sto eseguendo un algoritmo. Ora, la dimensione dell'heap JVM è pari a 4 GB.

Non riesco a elaborare tutti gli SKU in uno scatto poiché mi occorrerà molta più memoria. Quindi, divido il problema impostato in lotti più piccoli. Ogni lotto avrà tutti gli SKU correlati che devono essere elaborati insieme.

Ora eseguo diverse iterazioni per elaborare l'intero set di dati. Diciamo, se ogni lotto contiene ca. 5000 SKU, avrò 200 iterazioni/cicli. Tutti i dati relativi alle 5000 SKU sono necessari fino al completamento dell'elaborazione del batch. Ma quando inizia il prossimo lotto, i precedenti dati "batch" non sono richiesti e quindi possono essere raccolti.

Questo è lo sfondo del problema. Ora, arrivando al particolare problema di prestazioni dovuto a GC - Ogni lotto impiega circa 2-3 secondi per terminare. Ora, in questo momento, GC non è in grado di liberare alcun oggetto dal momento che tutti i dati sono necessari fino alla fine dell'elaborazione di un particolare batch. Quindi, GC sta spostando tutti questi oggetti sul vecchio Gen (Se guardo il profiler di yourkit, c'è quasi nulla nella nuova Gen). Quindi, la vecchia generazione sta crescendo più velocemente e serve un GC completo, il che rende il mio programma molto lento. C'è un modo per mettere a punto il GC in questo caso o può cambiare il mio codice per eseguire l'allocazione della memoria in un modo diverso?

PS: se ogni lotto è molto piccolo, non vedo questo problema. Credo che questo sia dovuto al fatto che il GC è in grado di liberare gli oggetti abbastanza velocemente dal completamento del batch più veloce e quindi non necessario per spostare oggetti nel vecchio gen.

+0

Il ** profiler ** indica che è stato necessario più del 10% del tempo necessario per raccogliere i rifiuti? O è una supposizione? – RobAu

+0

Modifica la soglia di durata. Come dipende dal tuo GC - quale GC stai usando? –

+0

Qual è la durata del Full GC? –

risposta

3

First Google hit indica che è possibile utilizzare -XX:NewRatio per impostare una dimensione di nuova generazione più grande rispetto alla vecchia generazione.

+1

Non credi che aumenti di nuovo la dimensione della generazione aumenterà i tempi di raccolta della nuova generazione. Se aumenti le dimensioni di una nuova gen molto più grande, allora stai trattando la nuova gen come vecchia generazione. Ci vorrà tempo simile al GC rispetto al tempo di GC vecchio gen. IMO qualsiasi politica di GC non sarebbe di grande aiuto in questo caso. Si prega di correggere se ho torto. –

+1

@nachiketkate buon punto. Non sono certamente un esperto ma la mia comprensione è sempre stata che [è risaputo che è più efficiente per GC giovani rispetto alle vecchie generazioni] (http://www.javaspecialists.eu/archive/Issue115.html). Ma forse quel paragone è ingiusto, supponendo che il giovane gen sia più piccolo di un vecchio. –

1

È necessario regolare -XX: NewRatio come indicato nell'altra risposta.

È possibile iniziare con l'impostazione di questo -XX: NewRatio = 1 che significa che il vecchio gen e il giovane gen dividono equamente la memoria heap disponibile.

Maggiori dettagli su come questo flag funziona insieme ad altre bandiere di regolazione della memoria: https://docs.oracle.com/cd/E19900-01/819-4742/abeik/index.html

+0

Già giocato con New Ratio ... Aiutato in parte ma marginale allo – Shiladitya

+0

quando dici marginale, quali sono i NewRatios che hai provato? Qual è stato il miglioramento? – Vijay

+0

Sto ottenendo le migliori prestazioni con NEWRATIO = 3/4 – Shiladitya

1

Considerare l'utilizzo object pool pattern.

I.e. creare un pull di 5000 SKU, quindi per ogni lotto inizializzare ciascuno di questi oggetti con nuovi dati. In questo modo non avrai problemi con GC dato che pull è tutto ciò che devi assegnare.

+0

Grazie, sto provando qualcosa di simile. Non molto successo però – Shiladitya

0

alcuni consigli:

  1. Verificare la presenza di perdite di memoria con gli strumenti di profiling come visualvm o MAT
  2. Se non si dispone di perdite di memoria, controllo della memoria corrente è sufficiente o meno. In caso contrario, allocare memoria sufficiente.
  3. Dalla dichiarazione del problema, oldGen è in crescita e sta causando FullGC. Non hai citato il garbage collector che stai usando.Dato che stai usando memoria> = 4 GB, dovresti provare l'alrogitmo G1GC. in G1GC, è possibile mantenere la maggior parte dei valori predefiniti tranne la configurazione di parametri chiave come pause time goal, region size, parallel gc threads etc.

fare riferimento a questa domanda SE per maggiori dettagli:

Java 7 (JDK 7) garbage collection and documentation on G1

0

So che questo è po 'in ritardo, ma ancora ..

Ho suonato in giro un sacco con le opzioni JVM GC che ha contribuito a un po ' La cosa buona è che ho imparato molto di più su GC nel processo :)

Infine, ho fatto una sorta di pooling di oggetti. Poiché il lavoro viene elaborato in batch e ogni lotto ha approssimativamente le stesse dimensioni e utilizza lo stesso numero di oggetti, ho creato un pool di oggetti che è stato riciclato ogni lotto invece di creare e distruggere gli oggetti ogni lotto. Alla fine di ogni batch, sto semplicemente reimpostando gli oggetti (matrici su -1 ecc.). E all'inizio del batch successivo, sto riutilizzando quegli oggetti re-inizializzandoli. Inoltre, per il caso multi-thread, questi pool sono fatti per essere ThreadLocals per evitare il sovraccarico di sincronizzazione.