2013-10-16 14 views
6

Stiamo provando a modificare alcune opzioni di Garbage Collection Oracle JVM e uno sviluppatore ha provato a utilizzare -XX:PretenureSizeThreshold per assicurarsi che una vasta serie di oggetti sia stata inserita in Tenured subito. Sono abbastanza sicuro che l'ipotesi fosse che la dimensione dell'array uguaglia o superi la dimensione totale di tutti gli oggetti in essa contenuti.Come vengono gestiti gli array di oggetti Java?

Ma in Java, non sono matrici di oggetti solo matrici di riferimenti? Cioè ogni oggetto nell'array, così come l'oggetto stesso dell'array, è separato in memoria e trattato separatamente dal garbage collector? Penso che l'oggetto array possa ancora diventare abbastanza grande se ci sono milioni di voci, ma non dovrebbe essere vicino alla dimensione totale degli oggetti che "contiene" se ogni oggetto è molto più grande di un riferimento.

Penso che ci sia confusione, perché per quanto ne so, in C:

  1. E 'possibile avere una serie di struct s che realmente memorizzare i struct s.
  2. E 'anche possibile avere una serie di puntatori a struct s.

Sono sicuro che Java usa sempre 1. per matrici di tipi primitivi e usa sempre 2. per matrici di oggetti, mentre C può usare per qualsiasi tipo ...?

Cosa succede se utilizzo un append() s frequente (come nel caso in questione)? Viene solo copiata la matrice e non gli oggetti nell'array? Inoltre, quando l'array viene copiato, anche se il vecchio array era in Tenured, quello nuovo inizia in Eden, giusto?

+0

Sei sostanzialmente corretto. In Java una matrice di non primitivi è sempre una matrice di riferimenti.E se un ArrayList viene riallocato, il nuovo array inizia "fresco". (Questo non vuol dire che alcune JVM non abbiano scenari di casi speciali, ma che sarebbe praticamente una tantum e mirate a una situazione specifica (cioè di benchmark critico). –

risposta

5

Ma in Java, non sono matrici di oggetti solo matrici di riferimenti?

Solo riferimenti. Tutti gli oggetti sono allocati nell'heap, mai negli array o nello stack (almeno ufficialmente, l'ottimizzatore può utilizzare l'allocazione dello stack, se possibile, ma questo è trasparente).

non deve essere vicino alla dimensione totale degli oggetti che "contiene" se ciascun oggetto è molto più grande di un riferimento.

Sì, in Java ogni volta che si dice "assegna/archivia un oggetto", si intende il riferimento (puntatore nella terminologia C).

Cosa succede se utilizzo un ArrayList con frequenti append() s (come nel caso in questione)? Viene solo copiata la matrice e non gli oggetti nell'array?

La matrice viene copiata solo quando è necessario il ridimensionamento, vale a dire molto raramente e il costo ammortizzato è proporzionale al numero di inserti. Gli oggetti di riferimento non vengono mai copiati.

Inoltre, quando la matrice viene copiato, anche se il vecchio era in serie Titolare del nuovo inizia nel Eden, giusto?

Sì!

+0

Intendevi citare la stessa cosa due volte? Tuttavia, hai risposto a tutte le domande, quindi ho accettato :) –

+0

Wow. Sembra terribile, ma forse l'allocazione di Java è abbastanza buona da mantenere i dati adiacenti al massimo. Se no ... beh, questa è una tragedia di prestazioni perse. – Thumbz

+0

@Thumbz: Certo, l'allocatore colloca l'oggetto allocato in fila l'uno accanto all'altro (a meno che non debba ottenere un nuovo frammento di memoria). Ma poi arriva il GC di compattazione ... cerca anche di preservare la località, ma diventa più complicato. A volte può essere un problema, ma non dimenticare la [radice di tutte le cose cattive] (http://c2.com/cgi/wiki?PrematureOptimization). – maaartinus

2

Ma in Java, non sono matrici di oggetti solo matrici di riferimenti? Cioè ogni oggetto nell'array, così come l'oggetto stesso dell'array, è separato in memoria e trattato separatamente dal garbage collector?

Sì.

Penso che ci sia confusione, perché per quanto ne so, in C:

  1. E 'possibile avere una serie di struct che realmente memorizzano le strutture.
  2. È anche possibile avere una matrice di puntatori alle strutture.

Sono abbastanza sicuro che Java utilizza sempre 1. per gli array di tipi primitivi e utilizza sempre 2. per gli array di oggetti, mentre C può utilizzare per qualsiasi tipo ...?

Java, come C, in genere memorizza le matrici di tipi primitivi come matrici effettive con elementi di tali tipi. Quindi un array int[] con 10 elementi di solito riserva 10 × 4 byte per l'array, oltre a sovraccarico per l'intero oggetto array.

Le matrici di oggetti, tuttavia, sono come dici tu, array di riferimenti. Quindi un object[] di 10 elementi normalmente richiede 10 × 4 byte (o forse 10 × 8 byte su CPU a 64 bit) per l'array, oltre a sovraccarico, più spazio per ogni oggetto a cui ogni elemento non nullo fa riferimento. Ciò corrisponde in C a un array di puntatori .

(uso il termine "genere", perché, anche se è così che la maggior parte delle JVM lo fanno, non sono necessaria per allocare la memoria in qualsiasi modo particolare.)

essere consapevoli del fatto che Java non ha anche veri array multidimensionali come C (o C#). Un int[][] in Java è in realtà un array unidimensionale, in cui ogni elemento è un riferimento al proprio sottoarray int[]. In C, un int[][] è in realtà una matrice bidimensionale di numeri interi (dove le lunghezze di tutti tranne la prima dimensione devono essere conosciute al momento della compilazione).

Addendum

Si noti inoltre che, come dici tu, C può avere veri e propri array di struct, che non sono né i tipi primitivi né puntatori. Java non ha questa capacità.

2

L'utilizzo di -XX:PretenureSizeThreshold per la messa a punto è improbabile che possa essere di aiuto. Questo parametro si applica solo all'allocazione diretta dell'Eden, mentre la maggior parte dell'allocazione avviene in TLAB (Thread Local Allocation Buffer) e -XX:PretenureSizeThreshold viene ignorata.

TLAB potrebbe essere abbastanza grande per il thread che alloca attivamente la memoria (pochi megabyte).

È possibile modificare il dimensionamento TLAB, per ridurre questo effetto, ma ciò probabilmente causerebbe più danni che benefici.

+0

Wow. E ho pensato di scavare già un bel po 'della complessità di GC, solo per accedere ai TLAB di Google e imbattersi in [questo orribile post] (https://blogs.oracle.com/jonthecollector/entry/the_real_thing). Sono assolutamente d'accordo sul fatto che a quel livello (e alla maggior parte dei livelli) la VM sia la soluzione migliore. Grazie per il consiglio! –

Problemi correlati