Bene, ci sono diverse domande in una qui!
1 - Come vengono gestiti gli oggetti di breve durata?
Come affermato in precedenza, la JVM può gestire perfettamente una quantità enorme di oggetti di breve durata, poiché segue l' ipotesi generazionale debole .
Notare che stiamo parlando di oggetti che hanno raggiunto la memoria principale (heap). Non è sempre così. Molti oggetti che crei non lasciano nemmeno un registro della CPU. Ad esempio, considera questo ciclo for
for(int i=0, i<max, i++) {
// stuff that implies i
}
Non pensiamo allo srotolamento del loop (un'ottimizzazione che la JVM esegue pesantemente sul tuo codice). Se max
è uguale a Integer.MAX_VALUE
, l'esecuzione del ciclo potrebbe richiedere del tempo. comunque, ili
variabile non sfuggirà mai al blocco del ciclo. Pertanto la JVM inserirà quella variabile in un registro della CPU, la incrementerà regolarmente ma non la rimanderà mai alla memoria principale.
Quindi, creare milioni di oggetti non è un grosso problema se vengono utilizzati solo localmente. Saranno morti prima di essere conservati in Eden, quindi il GC non li noterà nemmeno.
2 - È utile ridurre l'overhead del GC?
Come al solito, dipende.
Innanzitutto, è necessario abilitare la registrazione GC per avere una visione chiara di ciò che sta accadendo. Puoi abilitarlo con -Xloggc:gc.log -XX:+PrintGCDetails
.
Se la tua applicazione trascorre molto tempo in un ciclo GC, allora, sì, ottimizza il GC, altrimenti potrebbe non valerne la pena.
Ad esempio, se hai un GC giovane ogni 100 ms che impiega 10 ms, trascorri il 10% del tuo tempo nel GC e hai 10 raccolte al secondo (che è enorme). In tal caso, non perderei tempo nella messa a punto del GC, poiché quei 10 GC / s sarebbero ancora lì.
3 - Qualche esperienza
Ho avuto un problema simile su un'applicazione che stava creando una quantità enorme di una determinata classe. Nei log GC, ho notato che la velocità di creazione dell'applicazione era di circa 3 GB / s, che è decisamente troppo (dai ... 3 gigabyte di dati al secondo?!).
Il problema: troppi GC frequenti causati dalla creazione di troppi oggetti.
Nel mio caso, ho collegato un profiler della memoria e ho notato che una classe rappresentava un'enorme percentuale di tutti i miei oggetti. Ho rintracciato le istanze per scoprire che questa classe era fondamentalmente una coppia di booleani avvolti in un oggetto. In quel caso, erano disponibili due soluzioni:
Rielabora l'algoritmo in modo da non restituire una coppia di booleani ma ho invece due metodi che restituiscono ogni booleano separatamente
Memorizza nella cache gli oggetti, sapendo che c'erano solo 4 istanze diverse
Ho scelto il secondo, in quanto ha avuto il minimo impatto sull'applicazione ed è stato facile da introdurre. Mi ci sono voluti pochi minuti per mettere una factory con una cache non thread-safe (non avevo bisogno di thread safety poiché alla fine avrei avuto solo 4 istanze diverse).
Il tasso di allocazione è sceso a 1 GB / s, così come la frequenza dei giovani GC (divisa per 3).
Spero che aiuti !