JVM が char[] に基づいて文字列の作成を実装する方法に関連する質問に続いて、char[] が新しい文字列の内部にコピーされるときに反復が行われないことを述べました。System.arraycopy が最終的に呼び出されるためです。 memcpy などの関数を使用して、ネイティブの実装依存レベルで目的のメモリをコピーします (元の質問)。
それを自分の目で確認したかったので、Openjdk 7 のソース コードをダウンロードして閲覧を開始しました。OpenJDK C++ ソース コードの System.arraycopy の実装を次の場所で見つけました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
要素が型チェックを必要としない場合 (たとえば、プリミティブ データ型配列の場合)、Copy::conjoin_oops_atomic が呼び出されます。
Copy::conjoint_oops_atomic
関数は「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);
}
OS/アーキテクチャに基づいて、コピー操作の実装が異なるため、現在はプラットフォームに依存しています。例として Windows を使用します。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--;
}
}
}
そして...驚いたことに、要素 (oop 値) を反復処理し、それらを 1 つずつ (一見) コピーします。配列内の要素を繰り返し処理することによって、ネイティブ レベルであってもコピーが行われる理由を誰かが説明できますか?