जेवीएम स्ट्रिंग्स के आधार पर स्ट्रिंग्स के निर्माण के तरीके से संबंधित एक प्रश्न के बाद, मैंने उल्लेख किया है कि जब कोई [char] नई स्ट्रिंग के इंटीरियर पर कॉपी हो जाता है तो कोई पुनरावृत्ति नहीं होती है , क्योंकि System.arraycopy को अंततः बुलाया जाता है, जो किसी मूल, कार्यान्वयन-निर्भर स्तर (the original question) पर memcpy जैसे फ़ंक्शन का उपयोग करके वांछित स्मृति की प्रतिलिपि बनाता है।System.arraycopy के OpenJDK कार्यान्वयन
मैं इसे अपने लिए जांचना चाहता था, इसलिए मैंने ओपनजेड 7 स्रोत कोड डाउनलोड किया और इसे ब्राउज़ करना शुरू कर दिया। मैं OpenJDK सी ++ स्रोत कोड में 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
तत्वों कोई प्रकार चेक (कि उदाहरण, आदिम डेटा प्रकार सरणियों के लिए, के साथ मामला है), कॉपी की जरूरत है: : 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);
}
अब हम मंच निर्भर कर रहे हैं, के रूप में प्रति आपरेशन एक अलग कार्यान्वयन, ओएस/वास्तुकला पर आधारित है। मैं विंडोज के साथ एक उदाहरण के रूप में जाऊंगा। 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 मान) के माध्यम से iterates, उनमें से एक (प्रतीत होता है) के बाद एक को कॉपी। क्या कोई समझा सकता है कि सरणी में तत्वों के माध्यम से, मूल स्तर पर, प्रतिलिपि क्यों की जाती है?
वाह, धन्यवाद! यह पहली बार ओपनजेडीके कार्यान्वयन के माध्यम से थोड़ा उलझन में था, इसलिए मुझे कुछ गलत होने की उम्मीद थी। : पी तो आप कैसे सोचते हैं कि यह अनुकूलन होता है? मैंने कुछ परीक्षण किए, और सिस्टम।नियमित जावा मार्ग की तुलना में 10000 इंच की प्रतिलिपि बनाने में एरेकॉपी दो गुना तेज है। सी ++ में एक समान कार्य अभी भी काफी तेज़ है, हालांकि परिणाम विभिन्न संकलक अनुकूलन से प्रभावित हो सकते हैं। –
एक C++ प्रति एक कचरा कलेक्टर एक अलग थ्रेड पर चल भी नहीं है। यहां तक कि यदि आप कचरा उत्पन्न नहीं करते हैं, तो कलेक्टर को यह सत्यापित करने के लिए कुछ चक्र चुरा लेना पड़ता है कि इसका कोई काम नहीं है। मुझे यकीन है कि अगर संकलक arraycopy पाश unrolling है या यदि हार्डवेयर कैश में सरणी के पूरे ब्लॉक प्रीफ़ेचिंग है नहीं कर रहा हूँ। वास्तव में, माइक्रोकोड अनुकूलन के साथ, यह ज्ञान की मेरी गहराई से परे है। यही कारण है कि प्रोफाइलिंग इतना महत्वपूर्ण है, यह परीक्षण है कि यह साबित होता है कि अनुकूलन सार्थक था। –