Sau một câu hỏi liên quan đến cách JVM thực hiện tạo chuỗi dựa trên char [], tôi đã đề cập rằng không lặp lại diễn ra khi char [] được sao chép vào bên trong của chuỗi mới , kể từ khi System.arraycopy được gọi là cuối cùng, trong đó sao chép bộ nhớ mong muốn bằng cách sử dụng một chức năng như memcpy ở mức độ bản địa, phụ thuộc thực hiện (the original question).OpenJDK thực hiện System.arraycopy
Tôi muốn tự kiểm tra, vì vậy tôi đã tải xuống mã nguồn Openjdk 7 và bắt đầu duyệt qua. tôi thấy việc thực hiện System.arraycopy trong mã nguồn OpenJDK C++, trong 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
Nếu các yếu tố không cần kiểm tra kiểu (đó là trường hợp với, ví dụ, nguyên thủy kiểu dữ liệu mảng), Sao chép: : conjoin_oops_atomic được gọi.
Chức năng Copy::conjoint_oops_atomic
nằm trong '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);
}
Bây giờ chúng ta đang phụ thuộc nền tảng, như hoạt động sao chép có thực hiện khác nhau, dựa trên hệ điều hành/kiến trúc. Tôi sẽ đi với Windows làm ví dụ. 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--;
}
}
}
Và ... trước sự ngạc nhiên của tôi, nó lặp thông qua các yếu tố (các giá trị oop), sao chép chúng từng cái một (dường như). Ai đó có thể giải thích tại sao bản sao được thực hiện, ngay cả ở cấp bản địa, bằng cách lặp qua các phần tử trong mảng?
Wow, cảm ơn! Đó là một chút bối rối tìm kiếm thông qua việc thực hiện OpenJDK lần đầu tiên, vì vậy tôi đã mong đợi đã nhận được một cái gì đó sai trái. : P Vậy bạn nghĩ việc tối ưu hóa này diễn ra như thế nào? Tôi đã làm một số bài kiểm tra và Hệ thống.arraycopy nhanh gấp hai lần khi sao chép 10000 ints so với cách Java thông thường. Trong C++ một nhiệm vụ tương tự vẫn còn đáng chú ý nhanh hơn, mặc dù kết quả có thể bị ảnh hưởng bởi các tối ưu hóa trình biên dịch khác nhau. –
Bản sao C++ không có bộ thu gom rác chạy trên một chuỗi riêng biệt. Ngay cả khi bạn không tạo ra rác, người thu thập phải ăn cắp một vài chu kỳ để xác minh rằng nó không có việc gì để làm. Tôi không chắc chắn nếu trình biên dịch được unrolling loop arraycopy hoặc nếu phần cứng là prefetching toàn bộ khối của mảng vào bộ nhớ cache. Trong thực tế, với tối ưu hóa vi mã, nó vượt quá chiều sâu kiến thức của tôi. Đó là lý do tại sao hồ sơ là rất quan trọng, đó là thử nghiệm chứng minh việc tối ưu hóa là đáng giá. –