A seguito di una domanda relativa al modo in cui la JVM implementa creazione di stringhe in base a char [], ho detto che non l'iterazione avviene quando il char [] viene copiato all'interno della nuova stringa , dal momento che System.arraycopy viene chiamato alla fine, che copia la memoria desiderata utilizzando una funzione come memcpy a livello nativo, dipendente dall'implementazione (the original question).OpenJDK attuazione System.arraycopy
volevo controllare che per me, così ho scaricato il codice sorgente OpenJDK 7 e ha iniziato la navigazione esso. Ho trovato l'attuazione System.arraycopy nella OpenJDK codice sorgente C++, in openjdx/hotspot/src/share/vm/oops/objArrayKlass.cpp
:
if (stype == bound || Klass::cast(stype)->is_subtype_of(bound)) {
// elements are guaranteed to be subtypes, so no check necessary
bs->write_ref_array_pre(dst, length);
Copy::conjoint_oops_atomic(src, dst, length);
} else {
// slow case: need individual subtype checks
Se gli elementi non hanno bisogno di tipo controlli (questo è il caso con, per esempio, primitivi tipo di dati array), Copy: : conjoin_oops_atomic viene chiamato.
La funzione Copy::conjoint_oops_atomic
risiede nel 'copy.hpp':
// overloaded for UseCompressedOops
static void conjoint_oops_atomic(narrowOop* from, narrowOop* to, size_t count) {
assert(sizeof(narrowOop) == sizeof(jint), "this cast is wrong");
assert_params_ok(from, to, LogBytesPerInt);
pd_conjoint_jints_atomic((jint*)from, (jint*)to, count);
}
Ora siamo dipendenti dalla piattaforma, come l'operazione di copia dispone di un'implementazione diversa, basata su OS/architettura. Vado con Windows come esempio. openjdk\hotspot\src\os_cpu\windows_x86\vm\copy_windows_x86.inline.hpp
:
static void pd_conjoint_oops_atomic(oop* from, oop* to, size_t count) {
// Do better than this: inline memmove body NEEDS CLEANUP
if (from > to) {
while (count-- > 0) {
// Copy forwards
*to++ = *from++;
}
} else {
from += count - 1;
to += count - 1;
while (count-- > 0) {
// Copy backwards
*to-- = *from--;
}
}
}
E ... con mia grande sorpresa, che scorre gli elementi (i valori OOP), la copia di una per una (apparentemente). Qualcuno può spiegare perché la copia è fatta, anche a livello nativo, iterando attraverso gli elementi dell'array?
Wow, grazie! È stato un po 'difficile guardare per la prima volta attraverso l'implementazione di OpenJDK, quindi mi aspettavo di avere qualcosa di sbagliato. : P Quindi, come pensi che questo ottimizzazione avvenga? Ho fatto alcuni test e System.arraycopy è due volte più veloce nella copia di 10000 pollici rispetto a un normale modo Java. In C++ un'attività simile è ancora notevolmente più veloce, anche se i risultati potrebbero essere influenzati da varie ottimizzazioni del compilatore. –
Una copia C++ non ha un garbage collector in esecuzione su un thread separato. Anche se non generi rifiuti, il raccoglitore deve rubare alcuni cicli per verificare che non ha lavoro da fare. Non sono sicuro che il compilatore stia srotolando il ciclo di arraycopy o se l'hardware sta eseguendo il precaricamento dell'intero blocco dell'array nella cache. In effetti, con l'ottimizzazione del microcodice, è al di là della mia profondità di conoscenza. Ecco perché la profilatura è così importante, è il test che dimostra che l'ottimizzazione è stata utile. –