जावा में System.arraycopy मूल क्यों है?


84

मुझे जावा स्रोत में देखकर आश्चर्य हुआ कि System.arraycopy एक देशी विधि है।

बेशक कारण यह है क्योंकि यह तेज है। लेकिन क्या देशी तरकीब है जो कोड को नियोजित करने में सक्षम है जो इसे और तेज कर सकता है?

मूल सरणी पर सिर्फ लूप क्यों नहीं और प्रत्येक सूचक को नए सरणी में कॉपी करें - निश्चित रूप से यह धीमा और बोझिल नहीं है?

जवाबों:


82

मूल कोड में, इसे एक ही memcpy/ के साथ किया जा सकता है memmove, जैसा कि n अलग कॉपी ऑपरेशन के विपरीत है । प्रदर्शन में अंतर पर्याप्त है।


@ पैटर, इसलिए देशी कोड के भीतर आप जावा मेमोरी मॉडल के साथ फेटल कर सकते हैं? (मैं किसी भी मूल malarkey करने का कोई कारण नहीं था)
जेम्स बी

8
वास्तव में, केवल कुछ उप का arraycopyउपयोग किया जा सकता है memcpy/ memmove। दूसरों को कॉपी किए गए प्रत्येक तत्व के लिए रनटाइम प्रकार की जांच की आवश्यकता होती है।
स्टीफन सी

1
@ स्टीफन सी, दिलचस्प - ऐसा क्यों है?
पॉटर टॉर्क

3
@ Péter Török - एक Object[]आबादी से Stringवस्तुओं की नकल करने पर विचार करें String[]Java.sun.com/javase/6/docs/api/java/lang/…
स्टीफन C

3
पीटर, ऑब्जेक्ट [] और बाइट [] + चार [] सबसे अधिक बार कॉपी किए गए हैं, उनमें से किसी को भी स्पष्ट प्रकार की जांच की आवश्यकता नहीं है। संकलक तब तक स्मार्ट नहीं है जब तक कि जांच न हो और लगभग 99.9% मामले में ऐसा न हो। मजेदार हिस्सा छोटे आकार की प्रतियां हैं (कैश लाइन से कम) काफी प्रभावी हैं, इसलिए छोटे आकार के सामान के लिए "मेमसीपी" तेज होना वास्तव में महत्वपूर्ण है।
बेस्टसेल्स

16

यह जावा में नहीं लिखा जा सकता। मूल कोड ऑब्जेक्ट की सरणियों और प्राथमिकताओं के सरणियों के बीच के अंतर को अनदेखा या समाप्त करने में सक्षम है। जावा ऐसा नहीं कर सकता, कम से कम कुशलता से नहीं।

और यह एक के साथ नहीं लिखा जा सकता है memcpy(), क्योंकि ओवरलैपिंग सरणियों द्वारा आवश्यक शब्दार्थ के कारण।


5
ठीक है, memmoveतो। हालांकि मुझे नहीं लगता कि यह इस प्रश्न के संदर्भ में बहुत अंतर करता है।
पॉटर टॉर्क

याद नहीं () या तो, एक और जवाब पर @Stephen C की टिप्पणियां देखें।
लोर्ने

देखा कि पहले से ही, के बाद से हुआ है कि मेरे अपने जवाब;; लेकिन वैसे भी धन्यवाद।
पेटर तोर्क

1
@ गीक एरेप्स जो ओवरलैप करता है। यदि स्रोत और लक्ष्य सरणियाँ और समान और केवल ऑफ़सेट भिन्न हैं, तो व्यवहार सावधानी से निर्दिष्ट किया गया है, और मेमसीपी () का पालन नहीं करता है।
लोर्ने का

1
यह जावा में नहीं लिखा जा सकता है? ऑब्जेक्ट के उपवर्गों को संभालने के लिए कोई एक सामान्य विधि नहीं लिख सकता है, और फिर प्रत्येक आदिम प्रकारों के लिए एक?
माइकल डोरस्ट ऑक्ट

10

यह, निश्चित रूप से, कार्यान्वयन निर्भर है।

हॉटस्पॉट इसे "इंट्रिंसिक" के रूप में मानेगा और कॉल साइट पर कोड डालेगा। यह मशीन कोड है, पुराना C कोड धीमा नहीं है। इसका मतलब यह भी है कि विधि के हस्ताक्षर के साथ समस्याएं काफी हद तक दूर हो जाती हैं।

एक साधारण कॉपी लूप इतना सरल है कि उस पर स्पष्ट अनुकूलन लागू किया जा सकता है। उदाहरण के लिए लूप का अनियंत्रित होना। वास्तव में क्या होता है फिर से कार्यान्वयन निर्भर है।


2
यह एक बहुत ही सभ्य जवाब है :), esp। आंतरिकों का उल्लेख। डब्ल्यू / ओ उन्हें सरल पुनरावृत्ति तेजी से हो सकता है क्योंकि यह आमतौर पर JIT द्वारा किसी भी तरह से
अनियंत्रित है

4

अपने स्वयं के परीक्षणों में कई आयाम सरणियों की प्रतिलिपि बनाने के लिए System.arraycopy () लूप को इंटरलेयर करने की तुलना में 10 से 20 गुना तेज है:

float[][] foo = mLoadMillionsOfPoints(); // result is a float[1200000][9]
float[][] fooCpy = new float[foo.length][foo[0].length];
long lTime = System.currentTimeMillis();
System.arraycopy(foo, 0, fooCpy, 0, foo.length);
System.out.println("native duration: " + (System.currentTimeMillis() - lTime) + " ms");
lTime = System.currentTimeMillis();

for (int i = 0; i < foo.length; i++)
{
    for (int j = 0; j < foo[0].length; j++)
    {
        fooCpy[i][j] = foo[i][j];
    }
}
System.out.println("System.arraycopy() duration: " + (System.currentTimeMillis() - lTime) + " ms");
for (int i = 0; i < foo.length; i++)
{
    for (int j = 0; j < foo[0].length; j++)
    {
        if (fooCpy[i][j] != foo[i][j])
        {
            System.err.println("ERROR at " + i + ", " + j);
        }
    }
}

यह प्रिंट:

System.arraycopy() duration: 1 ms
loop duration: 16 ms

9
भले ही यह सवाल पुराना है, सिर्फ रिकॉर्ड के लिए: यह एक उचित बेंचमार्क नहीं है (अकेले सवाल करें कि क्या ऐसा बेंचमार्क पहली बार में समझ में आएगा)। System.arraycopyएक उथली प्रतिलिपि करता है (केवल आंतरिक s के संदर्भों कीfloat[] प्रतिलिपि बनाई जाती है), जबकि आपके नेस्टेड- forलूप एक गहरी प्रतिलिपि बनाते हैं (float द्वारा float) करते हैं। एक परिवर्तन का उपयोग करने fooCpy[i][j]में परिलक्षित होगा , लेकिन नेस्टेड- लूप का उपयोग नहीं किया जाएगा । fooSystem.arraycopyfor
मिसनर

4

कुछ कारण हैं:

  1. JIT मैन्युअल रूप से लिखित C कोड के रूप में कुशल निम्न स्तर कोड उत्पन्न करने की संभावना नहीं है। निम्न स्तर C का उपयोग बहुत सारे अनुकूलन को सक्षम कर सकता है जो सामान्य जेआईटी कंपाइलर के लिए असंभव है।

    हाथ से लिखी सी कार्यान्वयन (मेम्पी, लेकिन सिद्धांत समान है) की कुछ ट्रिक्स और गति तुलना के लिए इस लिंक को देखें: इस ऑप्टिमाइज़िंग मेम्पी की जांच करें गति में सुधार

  2. सी संस्करण सरणी सदस्यों के प्रकार और आकार से बहुत अधिक स्वतंत्र है। जावा में भी ऐसा करना संभव नहीं है क्योंकि स्मृति के कच्चे ब्लॉक के रूप में सरणी सामग्री प्राप्त करने का कोई तरीका नहीं है (जैसे। सूचक)।


1
जावा कोड अनुकूलित हो सकता है। वास्तव में वास्तव में क्या होता है मशीन कोड उत्पन्न होता है जो सी की तुलना में अधिक कुशल है
टॉम हैटिन -

मैं मानता हूं कि कभी-कभी JITed कोड बेहतर स्थानीय रूप से अनुकूलित होगा क्योंकि यह जानता है कि यह किस प्रोसेसर पर रननिम्ग है। हालांकि, चूंकि यह "बस समय में" है, इसलिए यह उन सभी गैर-स्थानीय अनुकूलन का उपयोग करने में सक्षम नहीं होगा जो निष्पादित करने में अधिक समय लेते हैं। इसके अलावा, यह कभी भी हाथ से तैयार किए गए सी कोड से मेल नहीं खा सकेगा (जो प्रोसेसर को भी ध्यान में रख सकता है और जेआईटी के लाभों को आंशिक रूप से नकार सकता है, या तो किसी विशिष्ट प्रोसेसर के लिए या किसी प्रकार के रनटाइम चेक के द्वारा)।
हिरोविजे प्रगासा

1
मुझे लगता है कि सन जेआईटी कंपाइलर टीम उनमें से कई बिंदुओं पर विवाद करेगी। उदाहरण के लिए, मेरा मानना ​​है कि हॉटस्पॉट अनावश्यक प्रेषण को हटाने के लिए वैश्विक अनुकूलन करता है, और ऐसा कोई कारण नहीं है कि JIT प्रोसेसर कोड को उत्पन्न नहीं कर सकता है। फिर बिंदु यह है कि एक जेआईटी कंपाइलर वर्तमान एप्लिकेशन रन के निष्पादन व्यवहार के आधार पर शाखा अनुकूलन कर सकता है।
स्टीफन सी

@ स्टेफेन सी - शाखा ऑप्टिमाइज़ेशन के बारे में उत्कृष्ट बिंदु, इसके अलावा आप इसी तरह के प्रभाव को प्राप्त करने के लिए C / C ++ कंपाइलर के साथ स्थिर प्रदर्शन प्रोफाइलिंग भी कर सकते हैं। मुझे यह भी लगता है कि हॉटस्पॉट के ऑपरेशन के 2 तरीके हैं - डेस्कटॉप एप्लिकेशन उचित स्टार्टअप समय प्राप्त करने के लिए सभी उपलब्ध अनुकूलन का उपयोग नहीं करेंगे, जबकि सर्वर अनुप्रयोगों को अधिक आक्रामक तरीके से अनुकूलित किया जाएगा। सभी में, आपको कुछ फायदे मिलते हैं, लेकिन आप कुछ को ढीला भी करते हैं।
ह्रविजे प्रेगेसा

1
System.arrayCopy C का उपयोग करके लागू नहीं किया गया है, जो इस उत्तर को अमान्य करता है
नितन वकार्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.